summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/Makefile.inc52
-rw-r--r--auto_tests/toxav_basic_test.c131
-rw-r--r--auto_tests/toxav_many.c120
-rw-r--r--configure.ac52
-rwxr-xr-xtoxav/msi.c708
-rwxr-xr-xtoxav/msi.h66
-rwxr-xr-xtoxav/toxav.c200
-rwxr-xr-xtoxav/toxav.h44
-rw-r--r--toxcore/DHT.c67
-rw-r--r--toxcore/Makefile.inc2
-rw-r--r--toxcore/Messenger.c46
-rw-r--r--toxcore/assoc.c89
-rw-r--r--toxcore/assoc.h2
-rw-r--r--toxcore/logger.c159
-rw-r--r--toxcore/logger.h86
-rw-r--r--toxcore/network.c153
-rw-r--r--toxcore/tox.c2
-rw-r--r--toxcore/util.c84
-rw-r--r--toxcore/util.h7
19 files changed, 1280 insertions, 790 deletions
diff --git a/auto_tests/Makefile.inc b/auto_tests/Makefile.inc
index a8771695..a29c1bec 100644
--- a/auto_tests/Makefile.inc
+++ b/auto_tests/Makefile.inc
@@ -1,8 +1,10 @@
1if BUILD_TESTS 1if BUILD_TESTS
2 2
3TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test 3#TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
4check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test 4#check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test
5 5
6TESTS = toxav_basic_test
7check_PROGRAMS = toxav_basic_test
6 8
7AUTOTEST_CFLAGS = \ 9AUTOTEST_CFLAGS = \
8 $(LIBSODIUM_CFLAGS) \ 10 $(LIBSODIUM_CFLAGS) \
@@ -19,58 +21,58 @@ AUTOTEST_LDADD = \
19 21
20 22
21if BUILD_AV 23if BUILD_AV
22TESTS += toxav_basic_test 24#TESTS += toxav_basic_test
23check_PROGRAMS += toxav_basic_test 25#check_PROGRAMS += toxav_basic_test
24AUTOTEST_LDADD += libtoxav.la 26AUTOTEST_LDADD += libtoxav.la
25endif 27endif
26 28
27messenger_autotest_SOURCES = ../auto_tests/messenger_test.c 29#messenger_autotest_SOURCES = ../auto_tests/messenger_test.c
28 30
29messenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS) 31#messenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS)
30 32
31messenger_autotest_LDADD = $(AUTOTEST_LDADD) 33#messenger_autotest_LDADD = $(AUTOTEST_LDADD)
32 34
33 35
34crypto_test_SOURCES = ../auto_tests/crypto_test.c 36#crypto_test_SOURCES = ../auto_tests/crypto_test.c
35 37
36crypto_test_CFLAGS = $(AUTOTEST_CFLAGS) 38#crypto_test_CFLAGS = $(AUTOTEST_CFLAGS)
37 39
38crypto_test_LDADD = $(AUTOTEST_LDADD) 40#crypto_test_LDADD = $(AUTOTEST_LDADD)
39 41
40 42
41network_test_SOURCES = ../auto_tests/network_test.c 43#network_test_SOURCES = ../auto_tests/network_test.c
42 44
43network_test_CFLAGS = $(AUTOTEST_CFLAGS) 45#network_test_CFLAGS = $(AUTOTEST_CFLAGS)
44 46
45network_test_LDADD = $(AUTOTEST_LDADD) 47#network_test_LDADD = $(AUTOTEST_LDADD)
46 48
47 49
48assoc_test_SOURCES = ../auto_tests/assoc_test.c 50#assoc_test_SOURCES = ../auto_tests/assoc_test.c
49 51
50assoc_test_CFLAGS = $(AUTOTEST_CFLAGS) 52#assoc_test_CFLAGS = $(AUTOTEST_CFLAGS)
51 53
52assoc_test_LDADD = $(AUTOTEST_LDADD) 54#assoc_test_LDADD = $(AUTOTEST_LDADD)
53 55
54 56
55onion_test_SOURCES = ../auto_tests/onion_test.c 57#onion_test_SOURCES = ../auto_tests/onion_test.c
56 58
57onion_test_CFLAGS = $(AUTOTEST_CFLAGS) 59#onion_test_CFLAGS = $(AUTOTEST_CFLAGS)
58 60
59onion_test_LDADD = $(AUTOTEST_LDADD) 61#onion_test_LDADD = $(AUTOTEST_LDADD)
60 62
61 63
62TCP_test_SOURCES = ../auto_tests/TCP_test.c 64#TCP_test_SOURCES = ../auto_tests/TCP_test.c
63 65
64TCP_test_CFLAGS = $(AUTOTEST_CFLAGS) 66#TCP_test_CFLAGS = $(AUTOTEST_CFLAGS)
65 67
66TCP_test_LDADD = $(AUTOTEST_LDADD) 68#TCP_test_LDADD = $(AUTOTEST_LDADD)
67 69
68 70
69tox_test_SOURCES = ../auto_tests/tox_test.c 71#tox_test_SOURCES = ../auto_tests/tox_test.c
70 72
71tox_test_CFLAGS = $(AUTOTEST_CFLAGS) 73#tox_test_CFLAGS = $(AUTOTEST_CFLAGS)
72 74
73tox_test_LDADD = $(AUTOTEST_LDADD) 75#tox_test_LDADD = $(AUTOTEST_LDADD)
74 76
75 77
76if BUILD_AV 78if BUILD_AV
diff --git a/auto_tests/toxav_basic_test.c b/auto_tests/toxav_basic_test.c
index f337217c..affe4dd2 100644
--- a/auto_tests/toxav_basic_test.c
+++ b/auto_tests/toxav_basic_test.c
@@ -12,6 +12,7 @@
12#include <assert.h> 12#include <assert.h>
13 13
14#include "../toxcore/tox.h" 14#include "../toxcore/tox.h"
15#include "../toxcore/logger.h"
15#include "../toxav/toxav.h" 16#include "../toxav/toxav.h"
16 17
17#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) 18#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
@@ -22,6 +23,7 @@
22#endif 23#endif
23 24
24 25
26
25typedef enum _CallStatus { 27typedef enum _CallStatus {
26 none, 28 none,
27 InCall, 29 InCall,
@@ -36,6 +38,7 @@ typedef struct _Party {
36 CallStatus status; 38 CallStatus status;
37 ToxAv *av; 39 ToxAv *av;
38 time_t *CallStarted; 40 time_t *CallStarted;
41 int call_index;
39} Party; 42} Party;
40 43
41typedef struct _Status { 44typedef struct _Status {
@@ -45,42 +48,41 @@ typedef struct _Status {
45 48
46void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) 49void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
47{ 50{
48 if (length == 15 && memcmp("ILIKESMALLTITS", data, 15) == 0) { 51 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
49 tox_add_friend_norequest(m, public_key); 52 tox_add_friend_norequest(m, public_key);
50 } 53 }
51} 54}
52 55
53 56
54/******************************************************************************/ 57/******************************************************************************/
55void callback_recv_invite ( void *_arg ) 58void callback_recv_invite ( uint32_t call_index, void *_arg )
56{ 59{
57 Status *cast = _arg; 60 Status *cast = _arg;
58 61
59 /* Bob always receives invite */ 62 /* Bob always receives invite */
60 cast->Bob.status = Ringing; 63 cast->Bob.status = Ringing;
64 cast->Bob.call_index = call_index;
61} 65}
62void callback_recv_ringing ( void *_arg ) 66void callback_recv_ringing ( uint32_t call_index, void *_arg )
63{ 67{
64 Status *cast = _arg; 68 Status *cast = _arg;
65 69
66 /* Alice always sends invite */ 70 /* Alice always sends invite */
67 cast->Alice.status = Ringing; 71 cast->Alice.status = Ringing;
68} 72}
69void callback_recv_starting ( void *_arg ) 73void callback_recv_starting ( uint32_t call_index, void *_arg )
70{ 74{
71 Status *cast = _arg; 75 Status *cast = _arg;
72 76
73 /* Alice always sends invite */ 77 /* Alice always sends invite */
74 printf("Call started on Alice side...\n"); 78 printf("Call started on Alice side...\n");
75 cast->Alice.status = InCall; 79 cast->Alice.status = InCall;
76 toxav_prepare_transmission(cast->Alice.av, 1); 80 toxav_prepare_transmission(cast->Alice.av, call_index, 1);
77} 81}
78void callback_recv_ending ( void *_arg ) 82void callback_recv_ending ( uint32_t call_index, void *_arg )
79{ 83{
80 Status *cast = _arg; 84 Status *cast = _arg;
81 85
82
83
84 if ( cast->Alice.status == Rejected) { 86 if ( cast->Alice.status == Rejected) {
85 printf ( "Call ended for Bob!\n" ); 87 printf ( "Call ended for Bob!\n" );
86 cast->Bob.status = Ended; 88 cast->Bob.status = Ended;
@@ -90,28 +92,28 @@ void callback_recv_ending ( void *_arg )
90 } 92 }
91} 93}
92 94
93void callback_recv_error ( void *_arg ) 95void callback_recv_error ( uint32_t call_index, void *_arg )
94{ 96{
95 ck_assert_msg(0, "AV internal error"); 97 ck_assert_msg(0, "AV internal error");
96} 98}
97 99
98void callback_call_started ( void *_arg ) 100void callback_call_started ( uint32_t call_index, void *_arg )
99{ 101{
100 Status *cast = _arg; 102 Status *cast = _arg;
101 103
102 /* Alice always sends invite */ 104 /* Alice always sends invite */
103 printf("Call started on Bob side...\n"); 105 printf("Call started on Bob side...\n");
104 cast->Bob.status = InCall; 106 cast->Bob.status = InCall;
105 toxav_prepare_transmission(cast->Bob.av, 1); 107 toxav_prepare_transmission(cast->Bob.av, call_index, 1);
106} 108}
107void callback_call_canceled ( void *_arg ) 109void callback_call_canceled ( uint32_t call_index, void *_arg )
108{ 110{
109 Status *cast = _arg; 111 Status *cast = _arg;
110 112
111 printf ( "Call Canceled for Bob!\n" ); 113 printf ( "Call Canceled for Bob!\n" );
112 cast->Bob.status = Cancel; 114 cast->Bob.status = Cancel;
113} 115}
114void callback_call_rejected ( void *_arg ) 116void callback_call_rejected ( uint32_t call_index, void *_arg )
115{ 117{
116 Status *cast = _arg; 118 Status *cast = _arg;
117 119
@@ -120,7 +122,7 @@ void callback_call_rejected ( void *_arg )
120 /* If Bob rejects, call is ended for alice and she sends ending */ 122 /* If Bob rejects, call is ended for alice and she sends ending */
121 cast->Alice.status = Rejected; 123 cast->Alice.status = Rejected;
122} 124}
123void callback_call_ended ( void *_arg ) 125void callback_call_ended ( uint32_t call_index, void *_arg )
124{ 126{
125 Status *cast = _arg; 127 Status *cast = _arg;
126 128
@@ -128,7 +130,7 @@ void callback_call_ended ( void *_arg )
128 cast->Bob.status = Ended; 130 cast->Bob.status = Ended;
129} 131}
130 132
131void callback_requ_timeout ( void *_arg ) 133void callback_requ_timeout ( uint32_t call_index, void *_arg )
132{ 134{
133 ck_assert_msg(0, "No answer!"); 135 ck_assert_msg(0, "No answer!");
134} 136}
@@ -142,9 +144,9 @@ void callback_requ_timeout ( void *_arg )
142 tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \ 144 tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \
143 switch ( step ) {\ 145 switch ( step ) {\
144 case 0: /* Alice */ printf("Alice is calling...\n");\ 146 case 0: /* Alice */ printf("Alice is calling...\n");\
145 toxav_call(status_control.Alice.av, 0, AliceCallType, 10); step++; break;\ 147 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, AliceCallType, 10); step++; break;\
146 case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\ 148 case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\
147 cur_time = time(NULL); toxav_answer(status_control.Bob.av, BobCallType); step++; } break; \ 149 cur_time = time(NULL); toxav_answer(status_control.Bob.av, status_control.Bob.call_index, BobCallType); step++; } break; \
148 case 2: /* Rtp transmission */ \ 150 case 2: /* Rtp transmission */ \
149 if (status_control.Bob.status == InCall && status_control.Alice.status == InCall) 151 if (status_control.Bob.status == InCall && status_control.Alice.status == InCall)
150 152
@@ -153,7 +155,7 @@ void callback_requ_timeout ( void *_arg )
153case 3: /* Wait for Both to have status ended */\ 155case 3: /* Wait for Both to have status ended */\
154if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); 156if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n");
155 157
156START_TEST(test_AV) 158START_TEST(test_AV_flows)
157{ 159{
158 long long unsigned int cur_time = time(NULL); 160 long long unsigned int cur_time = time(NULL);
159 Tox *bootstrap_node = tox_new(0); 161 Tox *bootstrap_node = tox_new(0);
@@ -166,7 +168,7 @@ START_TEST(test_AV)
166 tox_callback_friend_request(Alice, accept_friend_request, &to_compare); 168 tox_callback_friend_request(Alice, accept_friend_request, &to_compare);
167 uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; 169 uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
168 tox_get_address(Alice, address); 170 tox_get_address(Alice, address);
169 int test = tox_add_friend(Bob, address, (uint8_t *)"ILIKESMALLTITS", 15); 171 int test = tox_add_friend(Bob, address, (uint8_t *)"gentoo", 7);
170 172
171 ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); 173 ck_assert_msg(test == 0, "Failed to add friend error code: %i", test);
172 174
@@ -195,8 +197,8 @@ START_TEST(test_AV)
195 muhcaps.video_height = muhcaps.video_width = 128; 197 muhcaps.video_height = muhcaps.video_width = 128;
196 198
197 Status status_control = { 199 Status status_control = {
198 {none, toxav_new(Alice, &muhcaps), NULL}, 200 {none, toxav_new(Alice, &muhcaps, 1), NULL},
199 {none, toxav_new(Bob, &muhcaps), NULL}, 201 {none, toxav_new(Bob, &muhcaps, 1), NULL},
200 }; 202 };
201 203
202 204
@@ -235,23 +237,23 @@ START_TEST(test_AV)
235 */ 237 */
236 CALL_AND_START_LOOP(TypeAudio, TypeAudio) { 238 CALL_AND_START_LOOP(TypeAudio, TypeAudio) {
237 /* Both send */ 239 /* Both send */
238 toxav_send_audio(status_control.Alice.av, sample_payload, 10); 240 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10);
239 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 241 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10);
240 242
241 /* Both receive */ 243 /* Both receive */
242 int16_t storage[10]; 244 int16_t storage[10];
243 int recved; 245 int recved;
244 246
245 /* Payload from Alice */ 247 /* Payload from Bob */
246 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 248 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage);
247 249
248 if ( recved ) { 250 if ( recved ) {
249 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 251 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
250 memset(storage, 0, 10); 252 memset(storage, 0, 10);
251 } 253 }
252 254
253 /* Payload from Bob */ 255 /* Payload from Alice */
254 recved = toxav_recv_audio(status_control.Bob.av, 10, storage); 256 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage);
255 257
256 if ( recved ) { 258 if ( recved ) {
257 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 259 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
@@ -259,11 +261,11 @@ START_TEST(test_AV)
259 261
260 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 262 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
261 step++; /* This terminates the loop */ 263 step++; /* This terminates the loop */
262 toxav_kill_transmission(status_control.Alice.av); 264 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
263 toxav_kill_transmission(status_control.Bob.av); 265 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
264 266
265 /* Call over Alice hangs up */ 267 /* Call over Alice hangs up */
266 toxav_hangup(status_control.Alice.av); 268 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
267 } 269 }
268 } 270 }
269 TERMINATE_SCOPE() 271 TERMINATE_SCOPE()
@@ -274,10 +276,10 @@ START_TEST(test_AV)
274 */ 276 */
275 CALL_AND_START_LOOP(TypeAudio, TypeVideo) { 277 CALL_AND_START_LOOP(TypeAudio, TypeVideo) {
276 /* Both send */ 278 /* Both send */
277 toxav_send_audio(status_control.Alice.av, sample_payload, 10); 279 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10);
278 280
279 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 281 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10);
280 toxav_send_video(status_control.Bob.av, sample_image); 282 toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
281 283
282 /* Both receive */ 284 /* Both receive */
283 int16_t storage[10]; 285 int16_t storage[10];
@@ -285,7 +287,7 @@ START_TEST(test_AV)
285 int recved; 287 int recved;
286 288
287 /* Payload from Bob */ 289 /* Payload from Bob */
288 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 290 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage);
289 291
290 if ( recved ) { 292 if ( recved ) {
291 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 293 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
@@ -293,7 +295,7 @@ START_TEST(test_AV)
293 } 295 }
294 296
295 /* Video payload */ 297 /* Video payload */
296 toxav_recv_video(status_control.Alice.av, &video_storage); 298 toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
297 299
298 if ( video_storage ) { 300 if ( video_storage ) {
299 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 301 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
@@ -305,7 +307,7 @@ START_TEST(test_AV)
305 307
306 308
307 /* Payload from Alice */ 309 /* Payload from Alice */
308 recved = toxav_recv_audio(status_control.Bob.av, 10, storage); 310 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage);
309 311
310 if ( recved ) { 312 if ( recved ) {
311 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 313 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
@@ -313,11 +315,11 @@ START_TEST(test_AV)
313 315
314 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 316 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
315 step++; /* This terminates the loop */ 317 step++; /* This terminates the loop */
316 toxav_kill_transmission(status_control.Alice.av); 318 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
317 toxav_kill_transmission(status_control.Bob.av); 319 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
318 320
319 /* Call over Alice hangs up */ 321 /* Call over Alice hangs up */
320 toxav_hangup(status_control.Alice.av); 322 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
321 } 323 }
322 } 324 }
323 TERMINATE_SCOPE() 325 TERMINATE_SCOPE()
@@ -328,11 +330,11 @@ START_TEST(test_AV)
328 */ 330 */
329 CALL_AND_START_LOOP(TypeVideo, TypeVideo) { 331 CALL_AND_START_LOOP(TypeVideo, TypeVideo) {
330 /* Both send */ 332 /* Both send */
331 toxav_send_audio(status_control.Alice.av, sample_payload, 10); 333 toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10);
332 toxav_send_video(status_control.Alice.av, sample_image); 334 toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image);
333 335
334 toxav_send_audio(status_control.Bob.av, sample_payload, 10); 336 toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10);
335 toxav_send_video(status_control.Bob.av, sample_image); 337 toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image);
336 338
337 /* Both receive */ 339 /* Both receive */
338 int16_t storage[10]; 340 int16_t storage[10];
@@ -340,7 +342,7 @@ START_TEST(test_AV)
340 int recved; 342 int recved;
341 343
342 /* Payload from Bob */ 344 /* Payload from Bob */
343 recved = toxav_recv_audio(status_control.Alice.av, 10, storage); 345 recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage);
344 346
345 if ( recved ) { 347 if ( recved ) {
346 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ 348 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/
@@ -348,7 +350,7 @@ START_TEST(test_AV)
348 } 350 }
349 351
350 /* Video payload */ 352 /* Video payload */
351 toxav_recv_video(status_control.Alice.av, &video_storage); 353 toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage);
352 354
353 if ( video_storage ) { 355 if ( video_storage ) {
354 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 356 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
@@ -360,14 +362,14 @@ START_TEST(test_AV)
360 362
361 363
362 /* Payload from Alice */ 364 /* Payload from Alice */
363 recved = toxav_recv_audio(status_control.Bob.av, 10, storage); 365 recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage);
364 366
365 if ( recved ) { 367 if ( recved ) {
366 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ 368 /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/
367 } 369 }
368 370
369 /* Video payload */ 371 /* Video payload */
370 toxav_recv_video(status_control.Bob.av, &video_storage); 372 toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage);
371 373
372 if ( video_storage ) { 374 if ( video_storage ) {
373 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || 375 /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 ||
@@ -378,11 +380,11 @@ START_TEST(test_AV)
378 380
379 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ 381 if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */
380 step++; /* This terminates the loop */ 382 step++; /* This terminates the loop */
381 toxav_kill_transmission(status_control.Alice.av); 383 toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index);
382 toxav_kill_transmission(status_control.Bob.av); 384 toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index);
383 385
384 /* Call over Alice hangs up */ 386 /* Call over Alice hangs up */
385 toxav_hangup(status_control.Alice.av); 387 toxav_hangup(status_control.Alice.av, status_control.Alice.call_index);
386 } 388 }
387 } 389 }
388 TERMINATE_SCOPE() 390 TERMINATE_SCOPE()
@@ -408,7 +410,7 @@ START_TEST(test_AV)
408 switch ( step ) { 410 switch ( step ) {
409 case 0: /* Alice */ 411 case 0: /* Alice */
410 printf("Alice is calling...\n"); 412 printf("Alice is calling...\n");
411 toxav_call(status_control.Alice.av, 0, TypeAudio, 10); 413 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
412 step++; 414 step++;
413 break; 415 break;
414 \ 416 \
@@ -416,7 +418,7 @@ START_TEST(test_AV)
416 case 1: /* Bob */ 418 case 1: /* Bob */
417 if (status_control.Bob.status == Ringing) { 419 if (status_control.Bob.status == Ringing) {
418 printf("Bob rejects...\n"); 420 printf("Bob rejects...\n");
419 toxav_reject(status_control.Bob.av, "Who likes D's anyway?"); 421 toxav_reject(status_control.Bob.av, status_control.Bob.call_index, "Who likes D's anyway?");
420 step++; 422 step++;
421 } 423 }
422 424
@@ -450,7 +452,7 @@ START_TEST(test_AV)
450 switch ( step ) { 452 switch ( step ) {
451 case 0: /* Alice */ 453 case 0: /* Alice */
452 printf("Alice is calling...\n"); 454 printf("Alice is calling...\n");
453 toxav_call(status_control.Alice.av, 0, TypeAudio, 10); 455 toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10);
454 step++; 456 step++;
455 break; 457 break;
456 \ 458 \
@@ -458,7 +460,7 @@ START_TEST(test_AV)
458 case 1: /* Alice again */ 460 case 1: /* Alice again */
459 if (status_control.Bob.status == Ringing) { 461 if (status_control.Bob.status == Ringing) {
460 printf("Alice cancels...\n"); 462 printf("Alice cancels...\n");
461 toxav_cancel(status_control.Alice.av, 0, "Who likes D's anyway?"); 463 toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?");
462 step++; 464 step++;
463 } 465 }
464 466
@@ -484,20 +486,29 @@ END_TEST
484/*************************************************************************************************/ 486/*************************************************************************************************/
485 487
486 488
489/*************************************************************************************************/
490
491/*************************************************************************************************/
492
487 493
488Suite *tox_suite(void) 494Suite *tox_suite(void)
489{ 495{
490 Suite *s = suite_create("ToxAV"); 496 Suite *s = suite_create("ToxAV");
491 497
492 TCase *tc_av = tcase_create("A/V"); 498 TCase *tc_av_flows = tcase_create("AV_flows");
493 tcase_add_test(tc_av, test_AV); 499 tcase_add_test(tc_av_flows, test_AV_flows);
494 tcase_set_timeout(tc_av, 100); /* Timeout on 100 too much? */ 500 tcase_set_timeout(tc_av_flows, 100); /* Timeout on 100 too much? */
495 suite_add_tcase(s, tc_av); 501 suite_add_tcase(s, tc_av_flows);
502
503 TCase *tc_av_three_calls = tcase_create("AV_three_calls");
504 tcase_add_test(tc_av_three_calls, test_AV_three_calls);
505 tcase_set_timeout(tc_av_three_calls, 100); /* Timeout on 100 too much? */
506 suite_add_tcase(s, tc_av_three_calls);
496 507
497 return s; 508 return s;
498} 509}
499int main(int argc, char *argv[]) 510int main(int argc, char *argv[])
500{ 511{
501 Suite *tox = tox_suite(); 512 Suite *tox = tox_suite();
502 SRunner *test_runner = srunner_create(tox); 513 SRunner *test_runner = srunner_create(tox);
503 514
diff --git a/auto_tests/toxav_many.c b/auto_tests/toxav_many.c
new file mode 100644
index 00000000..a5a32945
--- /dev/null
+++ b/auto_tests/toxav_many.c
@@ -0,0 +1,120 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <sys/types.h>
6#include <stdint.h>
7#include <string.h>
8#include <stdio.h>
9#include <check.h>
10#include <stdlib.h>
11#include <time.h>
12#include <assert.h>
13
14#include "../toxcore/tox.h"
15#include "../toxcore/logger.h"
16#include "../toxav/toxav.h"
17
18#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
19#define c_sleep(x) Sleep(1*x)
20#else
21#include <unistd.h>
22#define c_sleep(x) usleep(1000*x)
23#endif
24
25
26
27typedef enum _CallStatus {
28 none,
29 InCall,
30 Ringing,
31 Ended,
32 Rejected,
33 Cancel
34
35} CallStatus;
36
37typedef struct _Party {
38 CallStatus status;
39 ToxAv *av;
40 time_t *CallStarted;
41 int call_index;
42} Party;
43
44typedef struct _Status {
45 Party Alice;
46 Party Bob;
47} Status;
48
49void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
50{
51 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
52 tox_add_friend_norequest(m, public_key);
53 }
54}
55
56
57/******************************************************************************/
58void callback_recv_invite ( uint32_t call_index, void *_arg )
59{
60 Party *cast = _arg;
61
62 cast->status = Ringing;
63 cast->call_index = call_index;
64}
65void callback_recv_ringing ( uint32_t call_index, void *_arg )
66{
67 Party *cast = _arg;
68
69 cast->status = Ringing;
70}
71void callback_recv_starting ( uint32_t call_index, void *_arg )
72{
73 Party *cast = _arg;
74
75 cast->status = InCall;
76 toxav_prepare_transmission(cast->av, call_index, 1);
77}
78void callback_recv_ending ( uint32_t call_index, void *_arg )
79{
80 Party *cast = _arg;
81
82 cast->status = Ended;
83}
84
85void callback_recv_error ( uint32_t call_index, void *_arg )
86{
87 ck_assert_msg(0, "AV internal error");
88}
89
90void callback_call_started ( uint32_t call_index, void *_arg )
91{
92 Party *cast = _arg;
93
94 cast->status = InCall;
95 toxav_prepare_transmission(cast->av, call_index, 1);
96}
97void callback_call_canceled ( uint32_t call_index, void *_arg )
98{
99 Party *cast = _arg;
100
101 cast->status = Cancel;
102}
103void callback_call_rejected ( uint32_t call_index, void *_arg )
104{
105 Party *cast = _arg;
106
107 cast->status = Rejected;
108}
109void callback_call_ended ( uint32_t call_index, void *_arg )
110{
111 Party *cast = _arg;
112
113 cast->status = Ended;
114}
115
116void callback_requ_timeout ( uint32_t call_index, void *_arg )
117{
118 ck_assert_msg(0, "No answer!");
119}
120/*************************************************************************************************/
diff --git a/configure.ac b/configure.ac
index 34038517..f82f0a19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,6 +34,9 @@ BUILD_AV="yes"
34BUILD_PHONE="no" 34BUILD_PHONE="no"
35BUILD_TESTING="yes" 35BUILD_TESTING="yes"
36 36
37LOGGING="no"
38LOGGING_OUTNAM="libtoxcore.log"
39
37NCURSES_FOUND="no" 40NCURSES_FOUND="no"
38LIBCONFIG_FOUND="no" 41LIBCONFIG_FOUND="no"
39LIBCHECK_FOUND="no" 42LIBCHECK_FOUND="no"
@@ -80,6 +83,55 @@ AC_ARG_ENABLE([randombytes-stir],
80 ] 83 ]
81) 84)
82 85
86AC_ARG_ENABLE([logging],
87 [AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ],
88 [
89 if test "x$enableval" = "xyes"; then
90 LOGGING="yes"
91
92 AC_DEFINE([LOGGING], [], [If logging enabled])
93 AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
94 AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger])
95 fi
96 ]
97)
98
99AC_ARG_WITH(logger-level,
100 AC_HELP_STRING([--with-logger-level=LEVEL],
101 [Logger levels: INFO; DEBUG; WARNING; ERROR ]),
102 [
103 if test "x$LOGGING" = "xno"; then
104 AC_MSG_WARN([Logging disabled!])
105 else
106 if test "x$withval" = "xINFO"; then
107 AC_DEFINE([LOGGER_LEVEL], [INFO], [LoggerLevel value])
108
109 elif test "x$withval" = "xDEBUG"; then
110 AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value])
111
112 elif test "x$withval" = "xWARNING"; then
113 AC_DEFINE([LOGGER_LEVEL], [WARNING], [LoggerLevel value])
114
115 elif test "x$withval" = "xERROR"; then
116 AC_DEFINE([LOGGER_LEVEL], [ERROR], [LoggerLevel value])
117 else
118 AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG'])
119 fi
120 fi
121 ]
122)
123
124AC_ARG_WITH(logger-path,
125 AC_HELP_STRING([--with-logger-path=DIR],
126 [Path of logger output]),
127 [
128 if test "x$LOGGING" = "xno"; then
129 AC_MSG_WARN([Logging disabled!])
130 else
131 AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$withval""/""$LOGGING_OUTNAM"], [Output of logger])
132 fi
133 ]
134)
83 135
84PKG_PROG_PKG_CONFIG 136PKG_PROG_PKG_CONFIG
85 137
diff --git a/toxav/msi.c b/toxav/msi.c
index 26e301d3..ae6fcf84 100755
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -26,7 +26,9 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#define _BSD_SOURCE 29#include "../toxcore/logger.h"
30
31/*#define _BSD_SOURCE*/
30 32
31#include "msi.h" 33#include "msi.h"
32#include "event.h" 34#include "event.h"
@@ -120,10 +122,13 @@ static struct _Callbacks {
120 void* data; 122 void* data;
121} callbacks[11] = {0}; 123} callbacks[11] = {0};
122 124
123inline__ void invoke_callback(MSICallbackID id) 125inline__ void invoke_callback(uint32_t call_index, MSICallbackID id)
124{ 126{
125 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ 127 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/
126 if ( callbacks[id].function ) callbacks[id].function ( callbacks[id].data ); 128 if ( callbacks[id].function ) {
129 LOGGER_DEBUG("Invoking callback function: %d", id);
130 callbacks[id].function ( call_index, callbacks[id].data );
131 }
127} 132}
128 133
129/*static MSICallback callbacks[10] = {0};*/ 134/*static MSICallback callbacks[10] = {0};*/
@@ -230,7 +235,9 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
230 */ 235 */
231int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 236int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
232{ 237{
233 assert ( msg ); 238 if ( msg == NULL ) {
239 LOGGER_ERROR("Could not parse message: no storage!");
240 }
234 241
235 if ( data[length - 1] ) /* End byte must have value 0 */ 242 if ( data[length - 1] ) /* End byte must have value 0 */
236 return -1; 243 return -1;
@@ -271,7 +278,7 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
271 if ON_HEADER ( _it, msg->version, VERSION_FIELD, 7 ) 278 if ON_HEADER ( _it, msg->version, VERSION_FIELD, 7 )
272 else if ON_HEADER ( _it, msg->request, REQUEST_FIELD, 7 ) 279 else if ON_HEADER ( _it, msg->request, REQUEST_FIELD, 7 )
273 else if ON_HEADER ( _it, msg->callid, CALLID_FIELD, 7 ) 280 else if ON_HEADER ( _it, msg->callid, CALLID_FIELD, 7 )
274 } 281 }
275 break; 282 break;
276 283
277 case 8: { /* Response header */ 284 case 8: { /* Response header */
@@ -290,9 +297,13 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
290 break; 297 break;
291 298
292 default: 299 default:
300 LOGGER_ERROR("Unkown field value");
293 return -1; 301 return -1;
294 } 302 }
295 } else return -1; 303 } else {
304 LOGGER_ERROR("Invalid field byte or field size too large");
305 return -1;
306 }
296 307
297 /* If it's anything else return failure as the message is invalid */ 308 /* If it's anything else return failure as the message is invalid */
298 309
@@ -304,8 +315,9 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
304 315
305#define ALLOCATE_HEADER( var, mheader_value, t_size) \ 316#define ALLOCATE_HEADER( var, mheader_value, t_size) \
306var.header_value = calloc(sizeof *mheader_value, t_size); \ 317var.header_value = calloc(sizeof *mheader_value, t_size); \
307memcpy(var.header_value, mheader_value, t_size); \ 318if (var.header_value == NULL) { LOGGER_WARNING("Header allocation failed!"); } \
308var.size = t_size; 319else { memcpy(var.header_value, mheader_value, t_size); \
320var.size = t_size; }
309 321
310 322
311/** 323/**
@@ -316,7 +328,9 @@ var.size = t_size;
316 */ 328 */
317void free_message ( MSIMessage *msg ) 329void free_message ( MSIMessage *msg )
318{ 330{
319 assert ( msg ); 331 if ( msg == NULL ) {
332 LOGGER_ERROR("Tried to free empty message");
333 }
320 334
321 free ( msg->calltype.header_value ); 335 free ( msg->calltype.header_value );
322 free ( msg->request.header_value ); 336 free ( msg->request.header_value );
@@ -343,7 +357,11 @@ void free_message ( MSIMessage *msg )
343MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 357MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
344{ 358{
345 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 359 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
346 assert ( _retu ); 360
361 if ( _retu == NULL ) {
362 LOGGER_WARNING("Allocation failed!");
363 return NULL;
364 }
347 365
348 if ( type == TYPE_REQUEST ) { 366 if ( type == TYPE_REQUEST ) {
349 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 367 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) )
@@ -371,10 +389,17 @@ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
371 */ 389 */
372MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 390MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
373{ 391{
374 assert ( data ); 392 if ( data == NULL ) {
393 LOGGER_WARNING("Tried to parse empty message!");
394 return NULL;
395 }
375 396
376 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 397 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
377 assert ( _retu ); 398
399 if ( _retu == NULL ) {
400 LOGGER_WARNING("Allocation failed!");
401 return NULL;
402 }
378 403
379 memset ( _retu, 0, sizeof ( MSIMessage ) ); 404 memset ( _retu, 0, sizeof ( MSIMessage ) );
380 405
@@ -397,6 +422,42 @@ MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
397 422
398 423
399/** 424/**
425 * @brief Makes clear message presentation
426 *
427 * @param msg Message
428 * @param dest Dest string
429 * @return int
430 */
431int stringify_message(MSIMessage* msg, char* dest)
432{
433 #define HDR_TO_STR(__dest, __hdr) if (__hdr.header_value) {\
434 char nltstr[MSI_MAXMSG_SIZE]; memset(nltstr, '\0', MSI_MAXMSG_SIZE); int i = 0; \
435 for ( ; i < __hdr.size; i ++) nltstr[i] = (char)__hdr.header_value[i]; \
436 }
437
438 if ( !msg || !dest )
439 return -1;
440
441 HDR_TO_STR(dest, msg->version);
442 HDR_TO_STR(dest, msg->request);
443 HDR_TO_STR(dest, msg->response);
444 HDR_TO_STR(dest, msg->reason);
445 HDR_TO_STR(dest, msg->callid);
446 HDR_TO_STR(dest, msg->calltype);
447 HDR_TO_STR(dest, msg->cryptokey);
448 HDR_TO_STR(dest, msg->nonce);
449
450// if (msg->version.header_value) {
451// U8_TO_NLTCHAR(msg->version.header_value, msg->version.size, nltstr, MSI_MAXMSG_SIZE);
452// sprintf(dest, "Version: %s\n", nltstr);
453// }
454
455 return 0;
456}
457
458
459
460/**
400 * @brief Speaks for it self. 461 * @brief Speaks for it self.
401 * 462 *
402 * @param dest Container. 463 * @param dest Container.
@@ -413,10 +474,20 @@ uint8_t *append_header_to_string (
413 uint16_t value_len, 474 uint16_t value_len,
414 uint16_t *length ) 475 uint16_t *length )
415{ 476{
416 assert ( dest ); 477 if ( dest == NULL ) {
417 assert ( header_value ); 478 LOGGER_ERROR("No destination space!");
418 assert ( header_field ); 479 assert(dest);
419 480 }
481 if (header_value == NULL) {
482 LOGGER_ERROR("Empty header value");
483 return NULL;
484 }
485 if ( header_field == NULL ) {
486 LOGGER_ERROR("Empty header field");
487 return NULL;
488 }
489
490
420 const uint8_t *_hvit = header_value; 491 const uint8_t *_hvit = header_value;
421 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ 492 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/
422 493
@@ -477,10 +548,16 @@ if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)
477 * @param dest Destination. 548 * @param dest Destination.
478 * @return uint16_t It's final size. 549 * @return uint16_t It's final size.
479 */ 550 */
480uint16_t message_to_string ( MSIMessage *msg, uint8_t *dest ) 551uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest )
481{ 552{
482 assert ( msg ); 553 if (msg == NULL) {
483 assert ( dest ); 554 LOGGER_ERROR("Empty message!");
555 return 0;
556 }
557 if (dest == NULL ) {
558 LOGGER_ERROR("Empty destination!");
559 return 0;
560 }
484 561
485 uint8_t *_iterated = dest; 562 uint8_t *_iterated = dest;
486 uint16_t _size = 0; 563 uint16_t _size = 0;
@@ -525,7 +602,10 @@ GENERIC_SETTER_DEFINITION ( nonce )
525 */ 602 */
526void t_randomstr ( uint8_t *str, size_t size ) 603void t_randomstr ( uint8_t *str, size_t size )
527{ 604{
528 assert ( str ); 605 if (str == NULL) {
606 LOGGER_DEBUG("Empty destination!");
607 return;
608 }
529 609
530 static const uint8_t _bytes[] = 610 static const uint8_t _bytes[] =
531 "0123456789" 611 "0123456789"
@@ -607,14 +687,32 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
607 * @retval -1 Error occured. 687 * @retval -1 Error occured.
608 * @retval 0 Success. 688 * @retval 0 Success.
609 */ 689 */
610int send_message ( MSISession *session, MSIMessage *msg, uint32_t to ) 690int send_message ( MSISession *session, MSICall* call, MSIMessage *msg, uint32_t to )
611{ 691{
612 msi_msg_set_callid ( msg, session->call->id, CALL_ID_LEN ); 692 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN );
613 693
614 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 694 uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
615 uint16_t _length = message_to_string ( msg, _msg_string_final ); 695 uint16_t _length = message_to_send ( msg, _msg_string_final );
616 696
617 return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; 697 if (!_length) {
698 LOGGER_WARNING("Parsing message failed; nothing sent!");
699 return -1;
700 }
701
702 /*
703 LOGGER_SCOPE(
704 char cast[MSI_MAXMSG_SIZE];
705 stringify_message(msg, cast);
706 LOGGER_DEBUG("[Call: %s] [to: %u] Sending message: len: %d\n%s", call->id, to, _length, cast);
707 );*/
708
709
710 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) {
711 LOGGER_DEBUG("Sent message");
712 return 0;
713 }
714
715 return -1;
618} 716}
619 717
620 718
@@ -646,7 +744,7 @@ int call_id_bigger( const uint8_t* first, const uint8_t* second)
646 * @param peer_id The peer. 744 * @param peer_id The peer.
647 * @return void 745 * @return void
648 */ 746 */
649void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id ) 747void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
650{ 748{
651 if ( msg->calltype.header_value ) { 749 if ( msg->calltype.header_value ) {
652 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 750 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */
@@ -655,10 +753,10 @@ void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id )
655 hdrval[msg->calltype.size] = '\0'; 753 hdrval[msg->calltype.size] = '\0';
656 754
657 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) { 755 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
658 session->call->type_peer[peer_id] = type_audio; 756 call->type_peer[peer_id] = type_audio;
659 757
660 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 758 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) {
661 session->call->type_peer[peer_id] = type_video; 759 call->type_peer[peer_id] = type_video;
662 } else {} /* Error */ 760 } else {} /* Error */
663 } else {} /* Error */ 761 } else {} /* Error */
664} 762}
@@ -669,13 +767,17 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
669 767
670 switch ( status ) { 768 switch ( status ) {
671 case 0: { /* Went offline */ 769 case 0: { /* Went offline */
672 if ( session->call ) { 770 uint32_t j =0;
771 for ( ; j < session->max_calls; j ++ ) {
772
773 if ( !session->calls[j] ) continue;
774
673 int i = 0; 775 int i = 0;
674 776 for ( ; i < session->calls[j]->peer_count; i ++ )
675 for ( ; i < session->call->peer_count; i ++ ) 777 if ( session->calls[j]->peers[i] == friend_num ) {
676 if ( session->call->peers[i] == friend_num ) { 778 invoke_callback(j, MSI_OnPeerTimeout);
677 invoke_callback(MSI_OnPeerTimeout); 779 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
678 return; 780 return; /* TODO: On group calls change behaviour */
679 } 781 }
680 } 782 }
681 } 783 }
@@ -686,6 +788,18 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
686 } 788 }
687} 789}
688 790
791MSICall* find_call ( MSISession* session, uint8_t* call_id )
792{
793 if ( call_id == NULL ) return NULL;
794
795 uint32_t i = 0;
796 for (; i < session->max_calls; i ++ )
797 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 )
798 return session->calls[i];
799
800 return NULL;
801}
802
689/** 803/**
690 * @brief Sends error response to peer. 804 * @brief Sends error response to peer.
691 * 805 *
@@ -695,20 +809,22 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
695 * @return int 809 * @return int
696 * @retval 0 It's always success. 810 * @retval 0 It's always success.
697 */ 811 */
698int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) 812int handle_error ( MSISession *session, MSICall* call, MSICallError errid, uint32_t to )
699{ 813{
814 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
815
700 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 816 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) );
701 817
702 const uint8_t *_error_code_str = stringify_error_code ( errid ); 818 const uint8_t *_error_code_str = stringify_error_code ( errid );
703 819
704 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) ); 820 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) );
705 send_message ( session, _msg_error, to ); 821 send_message ( session, call, _msg_error, to );
706 free_message ( _msg_error ); 822 free_message ( _msg_error );
707 823
708 session->last_error_id = errid; 824 session->last_error_id = errid;
709 session->last_error_str = stringify_error ( errid ); 825 session->last_error_str = stringify_error ( errid );
710 826
711 invoke_callback(MSI_OnError); 827 invoke_callback(call->call_idx, MSI_OnError);
712 828
713 return 0; 829 return 0;
714} 830}
@@ -723,16 +839,16 @@ int handle_error ( MSISession *session, MSICallError errid, uint32_t to )
723 * @retval -1 No error. 839 * @retval -1 No error.
724 * @retval 0 Error occured and response sent. 840 * @retval 0 Error occured and response sent.
725 */ 841 */
726int has_call_error ( MSISession *session, MSIMessage *msg ) 842int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg )
727{ 843{
728 if ( !msg->callid.header_value ) { 844 if ( !msg->callid.header_value ) {
729 return handle_error ( session, error_no_callid, msg->friend_id ); 845 return handle_error ( session, call, error_no_callid, msg->friend_id );
730 846
731 } else if ( !session->call ) { 847 } else if ( !call ) {
732 return handle_error ( session, error_no_call, msg->friend_id ); 848 return handle_error ( session, call, error_no_call, msg->friend_id );
733 849
734 } else if ( memcmp ( session->call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { 850 } else if ( memcmp ( call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) {
735 return handle_error ( session, error_id_mismatch, msg->friend_id ); 851 return handle_error ( session, call, error_id_mismatch, msg->friend_id );
736 852
737 } 853 }
738 854
@@ -741,7 +857,7 @@ int has_call_error ( MSISession *session, MSIMessage *msg )
741 857
742 858
743/** 859/**
744 * @brief Function called at request timeout. 860 * @brief Function called at request timeout. If not called in thread it might cause trouble
745 * 861 *
746 * @param arg Control session 862 * @param arg Control session
747 * @return void* 863 * @return void*
@@ -752,16 +868,18 @@ void *handle_timeout ( void *arg )
752 * timers on these cancels and terminate call on 868 * timers on these cancels and terminate call on
753 * their timeout 869 * their timeout
754 */ 870 */
755 MSISession *_session = arg; 871 MSICall *_call = arg;
756 872
757 invoke_callback(MSI_OnRequestTimeout); 873 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id);
874
875 invoke_callback(_call->call_idx, MSI_OnRequestTimeout);
758 876
759 if ( _session && _session->call ) { 877 if ( _call && _call->session ) {
760 878
761 /* TODO: Cancel all? */ 879 /* TODO: Cancel all? */
762 /* uint16_t _it = 0; 880 /* uint16_t _it = 0;
763 for ( ; _it < _session->call->peer_count; _it++ ) */ 881 for ( ; _it < _session->call->peer_count; _it++ ) */
764 msi_cancel ( _session, _session->call->peers [0], "Request timedout" ); 882 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" );
765 } 883 }
766 884
767 pthread_exit(NULL); 885 pthread_exit(NULL);
@@ -798,14 +916,41 @@ void add_peer( MSICall *call, int peer_id )
798 */ 916 */
799MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 917MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
800{ 918{
801 assert ( session ); 919
802 assert ( peers ); 920 if (peers == 0) {
921 LOGGER_ERROR("No peers!");
922 return NULL;
923 }
924
925 uint32_t _call_idx = 0;
926 for (; _call_idx < session->max_calls; _call_idx ++) {
927 if ( !session->calls[_call_idx] ) {
928 session->calls[_call_idx] = calloc ( sizeof ( MSICall ), 1 );
929 break;
930 }
931 }
932
933 if ( _call_idx == session->max_calls ) {
934 LOGGER_WARNING("Reached maximum amount of calls!");
935 }
936
803 937
804 MSICall *_call = calloc ( sizeof ( MSICall ), 1 ); 938 MSICall *_call = session->calls[_call_idx];
939 _call->call_idx = _call_idx;
940
941 if ( _call == NULL ) {
942 LOGGER_WARNING("Allocation failed!");
943 return NULL;
944 }
945
805 _call->type_peer = calloc ( sizeof ( MSICallType ), peers ); 946 _call->type_peer = calloc ( sizeof ( MSICallType ), peers );
806 947
807 assert ( _call ); 948 if ( _call->type_peer == NULL ) {
808 assert ( _call->type_peer ); 949 LOGGER_WARNING("Allocation failed!");
950 return NULL;
951 }
952
953 _call->session = session;
809 954
810 /*_call->_participant_count = _peers;*/ 955 /*_call->_participant_count = _peers;*/
811 956
@@ -821,6 +966,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
821 966
822 pthread_mutex_init ( &_call->mutex, NULL ); 967 pthread_mutex_init ( &_call->mutex, NULL );
823 968
969 LOGGER_DEBUG("Started new call with index: %u", _call_idx);
824 return _call; 970 return _call;
825} 971}
826 972
@@ -833,51 +979,48 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
833 * @retval -1 Error occured. 979 * @retval -1 Error occured.
834 * @retval 0 Success. 980 * @retval 0 Success.
835 */ 981 */
836int terminate_call ( MSISession *session ) 982int terminate_call ( MSISession *session, MSICall *call )
837{ 983{
838 assert ( session ); 984 if ( !call ) {
839 985 LOGGER_WARNING("Tried to terminate non-existing call!");
840 if ( !session->call )
841 return -1; 986 return -1;
842 987 }
843 988
844 /* Check event loop and cancel timed events if there are any 989 /* Check event loop and cancel timed events if there are any
845 * NOTE: This has to be done before possibly 990 * NOTE: This has to be done before possibly
846 * locking the mutex the second time 991 * locking the mutex the second time
847 */ 992 */
848 event.timer_release ( session->call->request_timer_id ); 993 event.timer_release ( call->request_timer_id );
849 event.timer_release ( session->call->ringing_timer_id ); 994 event.timer_release ( call->ringing_timer_id );
850 995
851 /* Get a handle */ 996 /* Get a handle */
852 pthread_mutex_lock ( &session->call->mutex ); 997 pthread_mutex_lock ( &call->mutex );
853 998
854 MSICall *_call = session->call; 999 session->calls[call->call_idx]= NULL;
855 session->call = NULL;
856 1000
857 free ( _call->type_peer ); 1001 free ( call->type_peer );
858 free ( _call->key_local ); 1002 free ( call->key_local );
859 free ( _call->key_peer ); 1003 free ( call->key_peer );
860 free ( _call->peers); 1004 free ( call->peers);
861 1005
862 /* Release handle */ 1006 /* Release handle */
863 pthread_mutex_unlock ( &_call->mutex ); 1007 pthread_mutex_unlock ( &call->mutex );
864 1008
865 pthread_mutex_destroy ( &_call->mutex ); 1009 pthread_mutex_destroy ( &call->mutex );
866 1010
867 free ( _call ); 1011 free ( call );
868 1012
869 return 0; 1013 return 0;
870} 1014}
871 1015
872 1016
873/********** Request handlers **********/ 1017/********** Request handlers **********/
874int handle_recv_invite ( MSISession *session, MSIMessage *msg ) 1018int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg )
875{ 1019{
876 assert ( session ); 1020 LOGGER_DEBUG("Handling 'invite' on call: %s", call? (char*)call->id : "making new");
877
878 1021
879 if ( session->call ) { 1022 if ( call ) {
880 if ( session->call->peers[0] == msg->friend_id ) { 1023 if ( call->peers[0] == msg->friend_id ) {
881 /* The glare case. A calls B when at the same time 1024 /* The glare case. A calls B when at the same time
882 * B calls A. Who has advantage is set bey calculating 1025 * B calls A. Who has advantage is set bey calculating
883 * 'bigger' Call id and then that call id is being used in 1026 * 'bigger' Call id and then that call id is being used in
@@ -885,8 +1028,8 @@ int handle_recv_invite ( MSISession *session, MSIMessage *msg )
885 * as in he will wait the reponse from the other. 1028 * as in he will wait the reponse from the other.
886 */ 1029 */
887 1030
888 if ( call_id_bigger (session->call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1031 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */
889 terminate_call(session); 1032 terminate_call(session, call);
890 } 1033 }
891 else { 1034 else {
892 return 0; /* Wait for ringing from peer */ 1035 return 0; /* Wait for ringing from peer */
@@ -894,202 +1037,213 @@ int handle_recv_invite ( MSISession *session, MSIMessage *msg )
894 1037
895 } 1038 }
896 else { 1039 else {
897 handle_error ( session, error_busy, msg->friend_id ); 1040 handle_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
898 return 0; 1041 return 0;
899 } 1042 }
900 } 1043 }
901 1044
902 if ( !msg->callid.header_value ) { 1045 if ( !msg->callid.header_value ) {
903 handle_error ( session, error_no_callid, msg->friend_id ); 1046 handle_error ( session, call, error_no_callid, msg->friend_id );
904 return 0; 1047 return 0;
905 } 1048 }
906 1049
907 session->call = init_call ( session, 1, 0 ); 1050 MSICall* new_call = init_call ( session, 1, 0 );
908 memcpy ( session->call->id, msg->callid.header_value, CALL_ID_LEN ); 1051
909 session->call->state = call_starting; 1052 if ( !new_call ) {
1053 handle_error ( session, call, error_busy, msg->friend_id );
1054 return 0;
1055 }
1056
1057 memcpy ( new_call->id, msg->callid.header_value, CALL_ID_LEN );
1058 new_call->state = call_starting;
910 1059
911 add_peer( session->call, msg->friend_id); 1060 add_peer( new_call, msg->friend_id);
912 1061
913 flush_peer_type ( session, msg, 0 ); 1062 flush_peer_type ( new_call, msg, 0 );
914 1063
915 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1064 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) );
916 send_message ( session, _msg_ringing, msg->friend_id ); 1065 send_message ( session, new_call, _msg_ringing, msg->friend_id );
917 free_message ( _msg_ringing ); 1066 free_message ( _msg_ringing );
918 1067
919 invoke_callback(MSI_OnInvite); 1068 invoke_callback(new_call->call_idx, MSI_OnInvite);
920 1069
921 return 1; 1070 return 1;
922} 1071}
923int handle_recv_start ( MSISession *session, MSIMessage *msg ) 1072int handle_recv_start ( MSISession *session, MSICall* call, MSIMessage *msg )
924{ 1073{
925 assert ( session ); 1074 LOGGER_DEBUG("Handling 'start' on call: %s", call->id );
926 1075
927 if ( has_call_error ( session, msg ) == 0 ) 1076 if ( has_call_error ( session, call, msg ) == 0 )
928 return 0; 1077 return -1;
929 1078
930 if ( !msg->cryptokey.header_value ) 1079 if ( !msg->cryptokey.header_value )
931 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1080 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
932 1081
933 session->call->state = call_active; 1082 call->state = call_active;
934 1083
935 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); 1084 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
936 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); 1085 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES );
937 1086
938 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); 1087 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
939 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); 1088 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES );
940 1089
941 flush_peer_type ( session, msg, 0 ); 1090 flush_peer_type ( call, msg, 0 );
942 1091
943 invoke_callback(MSI_OnStart); 1092 invoke_callback(call->call_idx, MSI_OnStart);
944 1093
945 return 1; 1094 return 1;
946} 1095}
947int handle_recv_reject ( MSISession *session, MSIMessage *msg ) 1096int handle_recv_reject ( MSISession *session, MSICall* call, MSIMessage *msg )
948{ 1097{
949 assert ( session ); 1098 LOGGER_DEBUG("Handling 'reject' on call: %s", call->id );
950 1099
951 if ( has_call_error ( session, msg ) == 0 ) 1100 if ( has_call_error ( session, call, msg ) == 0 )
952 return 0; 1101 return 0;
953 1102
954 1103
955 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1104 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
956 send_message ( session, _msg_ending, msg->friend_id ); 1105 send_message ( session, call, _msg_ending, msg->friend_id );
957 free_message ( _msg_ending ); 1106 free_message ( _msg_ending );
958 1107
959 1108
960 invoke_callback(MSI_OnReject); 1109 invoke_callback(call->call_idx, MSI_OnReject);
961 /* 1110 /*
962 event.timer_release ( session->call->request_timer_id ); 1111 event.timer_release ( session->call->request_timer_id );
963 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1112 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
964 */ 1113 */
965 1114
966 terminate_call(session); 1115 terminate_call(session, call);
967 1116
968 return 1; 1117 return 1;
969} 1118}
970int handle_recv_cancel ( MSISession *session, MSIMessage *msg ) 1119int handle_recv_cancel ( MSISession *session, MSICall* call, MSIMessage *msg )
971{ 1120{
972 assert ( session ); 1121 LOGGER_DEBUG("Handling 'cancel' on call: %s", call->id );
973 1122
974 if ( has_call_error ( session, msg ) == 0 ) 1123 if ( has_call_error ( session, call, msg ) == 0 )
975 return 0; 1124 return 0;
976 1125
977 /* Act as end message */ 1126 /* Act as end message */
978 1127
979 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1128 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
980 send_message ( session, _msg_ending, msg->friend_id ); 1129 send_message ( session, call, _msg_ending, msg->friend_id );
981 free_message ( _msg_ending ); 1130 free_message ( _msg_ending );
982 1131
983 invoke_callback(MSI_OnCancel); 1132 invoke_callback(call->call_idx, MSI_OnCancel);
984 1133
985 terminate_call ( session ); 1134 terminate_call ( session, call );
986 1135
987 return 1; 1136 return 1;
988} 1137}
989int handle_recv_end ( MSISession *session, MSIMessage *msg ) 1138int handle_recv_end ( MSISession *session, MSICall* call, MSIMessage *msg )
990{ 1139{
991 assert ( session ); 1140 LOGGER_DEBUG("Handling 'end' on call: %s", call->id );
992 1141
993 if ( has_call_error ( session, msg ) == 0 ) 1142 if ( has_call_error ( session, call, msg ) == 0 )
994 return 0; 1143 return 0;
995 1144
996 1145
997 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1146 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
998 send_message ( session, _msg_ending, msg->friend_id ); 1147 send_message ( session, call, _msg_ending, msg->friend_id );
999 free_message ( _msg_ending ); 1148 free_message ( _msg_ending );
1000 1149
1001 invoke_callback(MSI_OnEnd); 1150 invoke_callback(call->call_idx, MSI_OnEnd);
1002 1151
1003 terminate_call ( session ); 1152 terminate_call ( session, call );
1004 return 1; 1153 return 1;
1005} 1154}
1006 1155
1007/********** Response handlers **********/ 1156/********** Response handlers **********/
1008int handle_recv_ringing ( MSISession *session, MSIMessage *msg ) 1157int handle_recv_ringing ( MSISession *session, MSICall* call, MSIMessage *msg )
1009{ 1158{
1010 assert ( session ); 1159 LOGGER_DEBUG("Handling 'ringing' on call: %s", call->id );
1011 1160
1012 if ( has_call_error ( session, msg ) == 0 ) 1161 if ( has_call_error ( session, call, msg ) == 0 )
1013 return 0; 1162 return 0;
1014 1163
1015 session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); 1164 call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms );
1016 1165
1017 invoke_callback(MSI_OnRinging); 1166 invoke_callback(call->call_idx, MSI_OnRinging);
1018 1167
1019 return 1; 1168 return 1;
1020} 1169}
1021int handle_recv_starting ( MSISession *session, MSIMessage *msg ) 1170int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg )
1022{ 1171{
1023 assert ( session ); 1172 LOGGER_DEBUG("Handling 'starting' on call: %s", call->id );
1024 1173
1025 if ( has_call_error ( session, msg ) == 0 ) 1174 if ( has_call_error ( session, call, msg ) == 0 )
1026 return 0; 1175 return 0;
1027 1176
1028 if ( !msg->cryptokey.header_value ) { 1177 if ( !msg->cryptokey.header_value ) {
1029 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1178 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
1030 } 1179 }
1031 1180
1032 /* Generate local key/nonce to send */ 1181 /* Generate local key/nonce to send */
1033 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); 1182 call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
1034 new_symmetric_key ( session->call->key_local ); 1183 new_symmetric_key ( call->key_local );
1035 1184
1036 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); 1185 call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
1037 new_nonce ( session->call->nonce_local ); 1186 new_nonce ( call->nonce_local );
1038 1187
1039 /* Save peer key/nonce */ 1188 /* Save peer key/nonce */
1040 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); 1189 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
1041 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); 1190 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES );
1042 1191
1043 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); 1192 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
1044 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); 1193 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES );
1045 1194
1046 session->call->state = call_active; 1195 call->state = call_active;
1047 1196
1048 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1197 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) );
1049 msi_msg_set_cryptokey ( _msg_start, session->call->key_local, crypto_secretbox_KEYBYTES ); 1198 msi_msg_set_cryptokey ( _msg_start, call->key_local, crypto_secretbox_KEYBYTES );
1050 msi_msg_set_nonce ( _msg_start, session->call->nonce_local, crypto_secretbox_NONCEBYTES ); 1199 msi_msg_set_nonce ( _msg_start, call->nonce_local, crypto_secretbox_NONCEBYTES );
1051 send_message ( session, _msg_start, msg->friend_id ); 1200 send_message ( session, call, _msg_start, msg->friend_id );
1052 free_message ( _msg_start ); 1201 free_message ( _msg_start );
1053 1202
1054 flush_peer_type ( session, msg, 0 ); 1203 flush_peer_type ( call, msg, 0 );
1055 1204
1056 invoke_callback(MSI_OnStarting); 1205 invoke_callback(call->call_idx, MSI_OnStarting);
1057 1206
1058 event.timer_release ( session->call->ringing_timer_id ); 1207 event.timer_release ( call->ringing_timer_id );
1059 1208
1060 return 1; 1209 return 1;
1061} 1210}
1062int handle_recv_ending ( MSISession *session, MSIMessage *msg ) 1211int handle_recv_ending ( MSISession *session, MSICall* call, MSIMessage *msg )
1063{ 1212{
1064 assert ( session ); 1213 LOGGER_DEBUG("Handling 'ending' on call: %s", call->id );
1065 1214
1066 if ( has_call_error ( session, msg ) == 0 ) 1215 if ( has_call_error ( session, call, msg ) == 0 )
1067 return 0; 1216 return 0;
1068 1217
1069 /* Stop timer */ 1218 /* Stop timer */
1070 event.timer_release ( session->call->request_timer_id ); 1219 event.timer_release ( call->request_timer_id );
1071 1220
1072 invoke_callback(MSI_OnEnding); 1221 invoke_callback(call->call_idx, MSI_OnEnding);
1073 1222
1074 /* Terminate call */ 1223 /* Terminate call */
1075 terminate_call ( session ); 1224 terminate_call ( session, call );
1076 1225
1077 return 1; 1226 return 1;
1078} 1227}
1079int handle_recv_error ( MSISession *session, MSIMessage *msg ) 1228int handle_recv_error ( MSISession *session, MSICall* call, MSIMessage *msg )
1080{ 1229{
1081 assert ( session ); 1230 if ( !call ) {
1082 assert ( session->call ); 1231 LOGGER_WARNING("Handling 'error' on non-existing call!");
1232 return -1;
1233 }
1234
1235 LOGGER_DEBUG("Handling 'error' on call: %s", call->id );
1083 1236
1084 /* Handle error accordingly */ 1237 /* Handle error accordingly */
1085 if ( msg->reason.header_value ) { 1238 if ( msg->reason.header_value ) {
1086 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value ); 1239 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value );
1087 session->last_error_str = stringify_error ( session->last_error_id ); 1240 session->last_error_str = stringify_error ( session->last_error_id );
1241 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1088 } 1242 }
1089 1243
1090 invoke_callback(MSI_OnEnding); 1244 invoke_callback(call->call_idx, MSI_OnEnding);
1091 1245
1092 terminate_call ( session ); 1246 terminate_call ( session, call );
1093 return 1; 1247 return 1;
1094} 1248}
1095 1249
@@ -1128,26 +1282,40 @@ int handle_recv_error ( MSISession *session, MSIMessage *msg )
1128 */ 1282 */
1129void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object ) 1283void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object )
1130{ 1284{
1285 LOGGER_DEBUG("Got msi message");
1131 /* Unused */ 1286 /* Unused */
1132 (void)messenger; 1287 (void)messenger;
1133 1288
1134 MSISession *_session = object; 1289 MSISession *_session = object;
1135 MSIMessage *_msg; 1290 MSIMessage *_msg;
1136 1291
1137 if ( !length ) return; 1292 if ( !length ) {
1293 LOGGER_WARNING("Lenght param negative");
1294 return;
1295 }
1138 1296
1139 _msg = parse_message ( data, length ); 1297 _msg = parse_message ( data, length );
1140 1298
1141 if ( !_msg ) return; 1299 if ( !_msg ) {
1300 LOGGER_WARNING("Error parsing message");
1301 return;
1302 } else {
1303 LOGGER_DEBUG("Successfully parsed message");
1304 }
1142 1305
1143 _msg->friend_id = source; 1306 _msg->friend_id = source;
1144 1307
1145 1308 /* Find what call */
1309 MSICall* _call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL;
1310
1146 /* Now handle message */ 1311 /* Now handle message */
1147 1312
1148 if ( _msg->request.header_value ) { /* Handle request */ 1313 if ( _msg->request.header_value ) { /* Handle request */
1149 1314
1150 if ( _msg->response.size > 32 ) goto free_end; 1315 if ( _msg->response.size > 32 ) {
1316 LOGGER_WARNING("Header size too big");
1317 goto free_end;
1318 }
1151 1319
1152 uint8_t _request_value[32]; 1320 uint8_t _request_value[32];
1153 1321
@@ -1155,26 +1323,30 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
1155 _request_value[_msg->request.size] = '\0'; 1323 _request_value[_msg->request.size] = '\0';
1156 1324
1157 if ( same ( _request_value, stringify_request ( invite ) ) ) { 1325 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1158 handle_recv_invite ( _session, _msg ); 1326 handle_recv_invite ( _session, _call, _msg );
1159 1327
1160 } else if ( same ( _request_value, stringify_request ( start ) ) ) { 1328 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1161 handle_recv_start ( _session, _msg ); 1329 handle_recv_start ( _session, _call, _msg );
1162 1330
1163 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { 1331 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1164 handle_recv_cancel ( _session, _msg ); 1332 handle_recv_cancel ( _session, _call, _msg );
1165 1333
1166 } else if ( same ( _request_value, stringify_request ( reject ) ) ) { 1334 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1167 handle_recv_reject ( _session, _msg ); 1335 handle_recv_reject ( _session, _call, _msg );
1168 1336
1169 } else if ( same ( _request_value, stringify_request ( end ) ) ) { 1337 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1170 handle_recv_end ( _session, _msg ); 1338 handle_recv_end ( _session, _call, _msg );
1339 } else {
1340 LOGGER_WARNING("Uknown request");
1341 goto free_end;
1171 } 1342 }
1172 1343
1173 else goto free_end;
1174
1175 } else if ( _msg->response.header_value ) { /* Handle response */ 1344 } else if ( _msg->response.header_value ) { /* Handle response */
1176 1345
1177 if ( _msg->response.size > 32 ) goto free_end; 1346 if ( _msg->response.size > 32 ) {
1347 LOGGER_WARNING("Header size too big");
1348 goto free_end;
1349 }
1178 1350
1179 uint8_t _response_value[32]; 1351 uint8_t _response_value[32];
1180 1352
@@ -1182,23 +1354,28 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
1182 _response_value[_msg->response.size] = '\0'; 1354 _response_value[_msg->response.size] = '\0';
1183 1355
1184 if ( same ( _response_value, stringify_response ( ringing ) ) ) { 1356 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1185 handle_recv_ringing ( _session, _msg ); 1357 handle_recv_ringing ( _session, _call, _msg );
1186 1358
1187 } else if ( same ( _response_value, stringify_response ( starting ) ) ) { 1359 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1188 handle_recv_starting ( _session, _msg ); 1360 handle_recv_starting ( _session, _call, _msg );
1189 1361
1190 } else if ( same ( _response_value, stringify_response ( ending ) ) ) { 1362 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1191 handle_recv_ending ( _session, _msg ); 1363 handle_recv_ending ( _session, _call, _msg );
1192 1364
1193 } else if ( same ( _response_value, stringify_response ( error ) ) ) { 1365 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1194 handle_recv_error ( _session, _msg ); 1366 handle_recv_error ( _session, _call, _msg );
1195 1367
1196 } else goto free_end; 1368 } else {
1369 LOGGER_WARNING("Uknown response");
1370 goto free_end;
1371 }
1197 1372
1198 /* Got response so cancel timer */ 1373 /* Got response so cancel timer */
1199 if ( _session->call ) 1374 if ( _call )
1200 event.timer_release ( _session->call->request_timer_id ); 1375 event.timer_release ( _call->request_timer_id );
1201 1376
1377 } else {
1378 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1202 } 1379 }
1203 1380
1204 free_end:free_message ( _msg ); 1381 free_end:free_message ( _msg );
@@ -1248,21 +1425,31 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd
1248 * @brief Start the control session. 1425 * @brief Start the control session.
1249 * 1426 *
1250 * @param messenger Tox* object. 1427 * @param messenger Tox* object.
1251 * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' 1428 * @param max_calls Amount of calls possible
1252 * @return MSISession* The created session. 1429 * @return MSISession* The created session.
1253 * @retval NULL Error occured. 1430 * @retval NULL Error occured.
1254 */ 1431 */
1255MSISession *msi_init_session ( Messenger* messenger ) 1432MSISession *msi_init_session ( Messenger* messenger, uint32_t max_calls )
1256{ 1433{
1257 assert ( messenger ); 1434 if (messenger == NULL) {
1435 LOGGER_ERROR("Could not init session on empty messenger!");
1436 return NULL;
1437 }
1258 1438
1439 if ( !max_calls) return NULL;
1440
1259 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); 1441 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 );
1260 assert ( _retu ); 1442
1443 if (_retu == NULL) {
1444 LOGGER_ERROR("Allocation failed!");
1445 return NULL;
1446 }
1261 1447
1262 _retu->messenger_handle = messenger; 1448 _retu->messenger_handle = messenger;
1263 _retu->agent_handler = NULL; 1449 _retu->agent_handler = NULL;
1264 1450
1265 _retu->call = NULL; 1451 _retu->calls = calloc( sizeof (MSICall*), max_calls );
1452 _retu->max_calls = max_calls;
1266 1453
1267 _retu->frequ = 10000; /* default value? */ 1454 _retu->frequ = 10000; /* default value? */
1268 _retu->call_timeout = 30000; /* default value? */ 1455 _retu->call_timeout = 30000; /* default value? */
@@ -1272,7 +1459,8 @@ MSISession *msi_init_session ( Messenger* messenger )
1272 1459
1273 /* This is called when remote terminates session */ 1460 /* This is called when remote terminates session */
1274 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); 1461 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu);
1275 1462
1463 LOGGER_DEBUG("New msi session: %p max calls: %u", _retu, max_calls);
1276 return _retu; 1464 return _retu;
1277} 1465}
1278 1466
@@ -1285,16 +1473,20 @@ MSISession *msi_init_session ( Messenger* messenger )
1285 */ 1473 */
1286int msi_terminate_session ( MSISession *session ) 1474int msi_terminate_session ( MSISession *session )
1287{ 1475{
1288 assert ( session ); 1476 if (session == NULL) {
1477 LOGGER_ERROR("Tried to terminate non-existing session");
1478 return -1;
1479 }
1289 1480
1290 int _status = 0; 1481 int _status = 0;
1291 1482
1292 /* If have call, cancel it */ 1483 /* If have calls, cancel them */
1293 if ( session->call ) { 1484 uint32_t idx = 0;
1485 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) {
1294 /* Cancel all? */ 1486 /* Cancel all? */
1295 uint16_t _it = 0; 1487 uint16_t _it = 0;
1296 for ( ; _it < session->call->peer_count; _it++ ) 1488 for ( ; _it < session->calls[idx]->peer_count; _it++ )
1297 msi_cancel ( session, session->call->peers [_it], "MSI session terminated!" ); 1489 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
1298 } 1490 }
1299 1491
1300 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); 1492 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
@@ -1313,35 +1505,39 @@ int msi_terminate_session ( MSISession *session )
1313 * @param friend_id The friend. 1505 * @param friend_id The friend.
1314 * @return int 1506 * @return int
1315 */ 1507 */
1316int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) 1508int msi_invite ( MSISession* session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id )
1317{ 1509{
1318 assert ( session ); 1510 LOGGER_DEBUG("Inviting friend: %u", friend_id);
1319 1511
1320 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1512 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) );
1513
1514 MSICall* _call = init_call ( session, 1, rngsec ); /* Just one for now */
1515 if ( !_call ) return -1; /* Cannot handle more calls */
1516
1517 *call_index = _call->call_idx;
1518
1519 t_randomstr ( _call->id, CALL_ID_LEN );
1321 1520
1322 session->call = init_call ( session, 1, rngsec ); /* Just one for now */ 1521 add_peer(_call, friend_id );
1323 t_randomstr ( session->call->id, CALL_ID_LEN );
1324
1325 add_peer(session->call, friend_id );
1326 1522
1327 session->call->type_local = call_type; 1523 _call->type_local = call_type;
1524
1328 /* Do whatever with message */ 1525 /* Do whatever with message */
1329
1330 if ( call_type == type_audio ) { 1526 if ( call_type == type_audio ) {
1331 msi_msg_set_calltype 1527 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1332 ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1333 } else { 1528 } else {
1334 msi_msg_set_calltype 1529 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1335 ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1336 } 1530 }
1337 1531
1338 send_message ( session, _msg_invite, friend_id ); 1532 send_message ( session, _call, _msg_invite, friend_id );
1339 free_message ( _msg_invite ); 1533 free_message ( _msg_invite );
1340 1534
1341 session->call->state = call_inviting; 1535 _call->state = call_inviting;
1342
1343 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
1344 1536
1537 _call->request_timer_id = event.timer_alloc ( handle_timeout, _call, m_deftout );
1538
1539 LOGGER_DEBUG("Invite sent");
1540
1345 return 0; 1541 return 0;
1346} 1542}
1347 1543
@@ -1350,29 +1546,37 @@ int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, ui
1350 * @brief Hangup active call. 1546 * @brief Hangup active call.
1351 * 1547 *
1352 * @param session Control session. 1548 * @param session Control session.
1549 * @param call_id To which call is this action handled.
1353 * @return int 1550 * @return int
1354 * @retval -1 Error occured. 1551 * @retval -1 Error occured.
1355 * @retval 0 Success. 1552 * @retval 0 Success.
1356 */ 1553 */
1357int msi_hangup ( MSISession *session ) 1554int msi_hangup ( MSISession* session, uint32_t call_index )
1358{ 1555{
1359 assert ( session ); 1556 LOGGER_DEBUG("Hanging up call: %u", call_index);
1360 1557
1361 if ( !session->call || session->call->state != call_active ) 1558 if ( call_index >= session->max_calls || !session->calls[call_index] ) {
1559 LOGGER_ERROR("Invalid call index!");
1560 return -1;
1561 }
1562
1563 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) {
1564 LOGGER_ERROR("No call with such index or call is not active!");
1362 return -1; 1565 return -1;
1566 }
1363 1567
1364 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1568 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) );
1365 1569
1366 /* hangup for each peer */ 1570 /* hangup for each peer */
1367 int _it = 0; 1571 int _it = 0;
1368 1572
1369 for ( ; _it < session->call->peer_count; _it ++ ) 1573 for ( ; _it < session->calls[call_index]->peer_count; _it ++ )
1370 send_message ( session, _msg_end, session->call->peers[_it] ); 1574 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1371 1575
1372 1576
1373 free_message ( _msg_end ); 1577 free_message ( _msg_end );
1374 1578
1375 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1579 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );
1376 1580
1377 return 0; 1581 return 0;
1378} 1582}
@@ -1382,15 +1586,22 @@ int msi_hangup ( MSISession *session )
1382 * @brief Answer active call request. 1586 * @brief Answer active call request.
1383 * 1587 *
1384 * @param session Control session. 1588 * @param session Control session.
1589 * @param call_id To which call is this action handled.
1385 * @param call_type Answer with Audio or Video(both). 1590 * @param call_type Answer with Audio or Video(both).
1386 * @return int 1591 * @return int
1387 */ 1592 */
1388int msi_answer ( MSISession *session, MSICallType call_type ) 1593int msi_answer ( MSISession* session, uint32_t call_index, MSICallType call_type )
1389{ 1594{
1390 assert ( session ); 1595 LOGGER_DEBUG("Answering call: %u", call_index);
1391 1596
1597 if ( call_index >= session->max_calls || !session->calls[call_index] ){
1598 LOGGER_ERROR("Invalid call index!");
1599 return -1;
1600 }
1601
1392 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1602 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) );
1393 session->call->type_local = call_type; 1603
1604 session->calls[call_index]->type_local = call_type;
1394 1605
1395 if ( call_type == type_audio ) { 1606 if ( call_type == type_audio ) {
1396 msi_msg_set_calltype 1607 msi_msg_set_calltype
@@ -1402,19 +1613,19 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1402 1613
1403 /* Now set the local encryption key and pass it with STARTING message */ 1614 /* Now set the local encryption key and pass it with STARTING message */
1404 1615
1405 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); 1616 session->calls[call_index]->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
1406 new_symmetric_key ( session->call->key_local ); 1617 new_symmetric_key ( session->calls[call_index]->key_local );
1407 1618
1408 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); 1619 session->calls[call_index]->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
1409 new_nonce ( session->call->nonce_local ); 1620 new_nonce ( session->calls[call_index]->nonce_local );
1410 1621
1411 msi_msg_set_cryptokey ( _msg_starting, session->call->key_local, crypto_secretbox_KEYBYTES ); 1622 msi_msg_set_cryptokey ( _msg_starting, session->calls[call_index]->key_local, crypto_secretbox_KEYBYTES );
1412 msi_msg_set_nonce ( _msg_starting, session->call->nonce_local, crypto_secretbox_NONCEBYTES ); 1623 msi_msg_set_nonce ( _msg_starting, session->calls[call_index]->nonce_local, crypto_secretbox_NONCEBYTES );
1413 1624
1414 send_message ( session, _msg_starting, session->call->peers[session->call->peer_count - 1] ); 1625 send_message ( session, session->calls[call_index], _msg_starting, session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1415 free_message ( _msg_starting ); 1626 free_message ( _msg_starting );
1416 1627
1417 session->call->state = call_active; 1628 session->calls[call_index]->state = call_active;
1418 1629
1419 return 0; 1630 return 0;
1420} 1631}
@@ -1424,21 +1635,27 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1424 * @brief Cancel request. 1635 * @brief Cancel request.
1425 * 1636 *
1426 * @param session Control session. 1637 * @param session Control session.
1638 * @param call_id To which call is this action handled.
1427 * @param reason Set optional reason header. Pass NULL if none. 1639 * @param reason Set optional reason header. Pass NULL if none.
1428 * @return int 1640 * @return int
1429 */ 1641 */
1430int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) 1642int msi_cancel ( MSISession *session, uint32_t call_index, uint32_t peer, const char *reason )
1431{ 1643{
1432 assert ( session ); 1644 LOGGER_DEBUG("Canceling call: %u; reason:", call_index, reason? reason : "Unknown");
1433 1645
1646 if ( call_index >= session->max_calls || !session->calls[call_index] ){
1647 LOGGER_ERROR("Invalid call index!");
1648 return -1;
1649 }
1650
1434 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1651 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
1435 1652
1436 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason)); 1653 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason));
1437 1654
1438 send_message ( session, _msg_cancel, peer ); 1655 send_message ( session, session->calls[call_index], _msg_cancel, peer );
1439 free_message ( _msg_cancel ); 1656 free_message ( _msg_cancel );
1440 1657
1441 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1658 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );
1442 1659
1443 return 0; 1660 return 0;
1444} 1661}
@@ -1448,20 +1665,26 @@ int msi_cancel ( MSISession *session, uint32_t peer, const char *reason )
1448 * @brief Reject request. 1665 * @brief Reject request.
1449 * 1666 *
1450 * @param session Control session. 1667 * @param session Control session.
1668 * @param call_id To which call is this action handled.
1451 * @return int 1669 * @return int
1452 */ 1670 */
1453int msi_reject ( MSISession *session, const uint8_t *reason ) 1671int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason )
1454{ 1672{
1455 assert ( session ); 1673 LOGGER_DEBUG("Rejecting call: %u; reason:", call_index, reason? (char*)reason : "Unknown");
1456 1674
1675 if ( call_index >= session->max_calls || !session->calls[call_index] ){
1676 LOGGER_ERROR("Invalid call index!");
1677 return -1;
1678 }
1679
1457 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1680 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) );
1458 1681
1459 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1682 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1);
1460 1683
1461 send_message ( session, _msg_reject, session->call->peers[session->call->peer_count - 1] ); 1684 send_message ( session, session->calls[call_index], _msg_reject, session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1462 free_message ( _msg_reject ); 1685 free_message ( _msg_reject );
1463 1686
1464 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1687 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );
1465 1688
1466 return 0; 1689 return 0;
1467} 1690}
@@ -1471,18 +1694,19 @@ int msi_reject ( MSISession *session, const uint8_t *reason )
1471 * @brief Terminate the current call. 1694 * @brief Terminate the current call.
1472 * 1695 *
1473 * @param session Control session. 1696 * @param session Control session.
1697 * @param call_id To which call is this action handled.
1474 * @return int 1698 * @return int
1475 */ 1699 */
1476int msi_stopcall ( MSISession *session ) 1700int msi_stopcall ( MSISession *session, uint32_t call_index )
1477{ 1701{
1478 assert ( session ); 1702 LOGGER_DEBUG("Stopping call index: %u", call_index);
1479 1703
1480 if ( !session->call ) 1704 if ( call_index >= session->max_calls || !session->calls[call_index] )
1481 return -1; 1705 return -1;
1482 1706
1483 /* just terminate it */ 1707 /* just terminate it */
1484 1708
1485 terminate_call ( session ); 1709 terminate_call ( session, session->calls[call_index] );
1486 1710
1487 return 0; 1711 return 0;
1488} \ No newline at end of file 1712} \ No newline at end of file
diff --git a/toxav/msi.h b/toxav/msi.h
index 37fc07a3..c74f9f11 100755
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -33,7 +33,7 @@
33#define CALL_ID_LEN 12 33#define CALL_ID_LEN 12
34 34
35 35
36typedef void ( *MSICallback ) ( void *arg ); 36typedef void ( *MSICallback ) ( uint32_t, void *arg );
37 37
38 38
39/** 39/**
@@ -62,32 +62,34 @@ typedef enum {
62 * @brief The call struct. 62 * @brief The call struct.
63 * 63 *
64 */ 64 */
65typedef struct _MSICall { /* Call info structure */ 65typedef struct _MSICall { /* Call info structure */
66 MSICallState state; 66 struct _MSISession* session; /* Session pointer */
67
68 MSICallState state;
67 69
68 MSICallType type_local; /* Type of payload user is ending */ 70 MSICallType type_local; /* Type of payload user is ending */
69 MSICallType *type_peer; /* Type of payload others are sending */ 71 MSICallType *type_peer; /* Type of payload others are sending */
70 72
71 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ 73 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
72 74
73 uint8_t *key_local; /* The key for encryption */ 75 uint8_t *key_local; /* The key for encryption */
74 uint8_t *key_peer; /* The key for decryption */ 76 uint8_t *key_peer; /* The key for decryption */
75 77
76 uint8_t *nonce_local; /* Local nonce */ 78 uint8_t *nonce_local; /* Local nonce */
77 uint8_t *nonce_peer; /* Peer nonce */ 79 uint8_t *nonce_peer; /* Peer nonce */
78 80
79 int ringing_tout_ms; /* Ringing timeout in ms */ 81 int ringing_tout_ms; /* Ringing timeout in ms */
80 82
81 int request_timer_id; /* Timer id for outgoing request/action */ 83 int request_timer_id; /* Timer id for outgoing request/action */
82 int ringing_timer_id; /* Timer id for ringing timeout */ 84 int ringing_timer_id; /* Timer id for ringing timeout */
83
84 pthread_mutex_t mutex; /* It's to be assumed that call will have
85 * seperate thread so add mutex
86 */
87 uint32_t *peers;
88 uint16_t peer_count;
89 85
86 pthread_mutex_t mutex; /* It's to be assumed that call will have
87 * seperate thread so add mutex
88 */
89 uint32_t *peers;
90 uint16_t peer_count;
90 91
92 uint32_t call_idx; /* Index of this call in MSISession */
91} MSICall; 93} MSICall;
92 94
93 95
@@ -97,8 +99,9 @@ typedef struct _MSICall { /* Call info structure */
97 */ 99 */
98typedef struct _MSISession { 100typedef struct _MSISession {
99 101
100 /* Call handler */ 102 /* Call handlers */
101 struct _MSICall *call; 103 struct _MSICall **calls;
104 uint32_t max_calls;
102 105
103 int last_error_id; /* Determine the last error */ 106 int last_error_id; /* Determine the last error */
104 const uint8_t *last_error_str; 107 const uint8_t *last_error_str;
@@ -151,10 +154,11 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat
151 * @brief Start the control session. 154 * @brief Start the control session.
152 * 155 *
153 * @param messenger Tox* object. 156 * @param messenger Tox* object.
157 * @param max_calls Amount of calls possible
154 * @return MSISession* The created session. 158 * @return MSISession* The created session.
155 * @retval NULL Error occured. 159 * @retval NULL Error occured.
156 */ 160 */
157MSISession *msi_init_session ( Messenger *messenger ); 161MSISession *msi_init_session ( Messenger *messenger, uint32_t max_calls );
158 162
159 163
160/** 164/**
@@ -170,62 +174,68 @@ int msi_terminate_session ( MSISession *session );
170 * @brief Send invite request to friend_id. 174 * @brief Send invite request to friend_id.
171 * 175 *
172 * @param session Control session. 176 * @param session Control session.
177 * @param call_index Set to new call index.
173 * @param call_type Type of the call. Audio or Video(both audio and video) 178 * @param call_type Type of the call. Audio or Video(both audio and video)
174 * @param rngsec Ringing timeout. 179 * @param rngsec Ringing timeout.
175 * @param friend_id The friend. 180 * @param friend_id The friend.
176 * @return int 181 * @return int
177 */ 182 */
178int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); 183int msi_invite ( MSISession *session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
179 184
180 185
181/** 186/**
182 * @brief Hangup active call. 187 * @brief Hangup active call.
183 * 188 *
184 * @param session Control session. 189 * @param session Control session.
190 * @param call_index To which call is this action handled.
185 * @return int 191 * @return int
186 * @retval -1 Error occured. 192 * @retval -1 Error occured.
187 * @retval 0 Success. 193 * @retval 0 Success.
188 */ 194 */
189int msi_hangup ( MSISession *session ); 195int msi_hangup ( MSISession *session, uint32_t call_index );
190 196
191 197
192/** 198/**
193 * @brief Answer active call request. 199 * @brief Answer active call request.
194 * 200 *
195 * @param session Control session. 201 * @param session Control session.
202 * @param call_index To which call is this action handled.
196 * @param call_type Answer with Audio or Video(both). 203 * @param call_type Answer with Audio or Video(both).
197 * @return int 204 * @return int
198 */ 205 */
199int msi_answer ( MSISession *session, MSICallType call_type ); 206int msi_answer ( MSISession *session, uint32_t call_index, MSICallType call_type );
200 207
201 208
202/** 209/**
203 * @brief Cancel request. 210 * @brief Cancel request.
204 * 211 *
205 * @param session Control session. 212 * @param session Control session.
213 * @param call_index To which call is this action handled.
206 * @param peer To which peer. 214 * @param peer To which peer.
207 * @param reason Set optional reason header. Pass NULL if none. 215 * @param reason Set optional reason header. Pass NULL if none.
208 * @return int 216 * @return int
209 */ 217 */
210int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); 218int msi_cancel ( MSISession* session, uint32_t call_index, uint32_t peer, const char* reason );
211 219
212 220
213/** 221/**
214 * @brief Reject request. 222 * @brief Reject request.
215 * 223 *
216 * @param session Control session. 224 * @param session Control session.
225 * @param call_index To which call is this action handled.
217 * @param reason Set optional reason header. Pass NULL if none. 226 * @param reason Set optional reason header. Pass NULL if none.
218 * @return int 227 * @return int
219 */ 228 */
220int msi_reject ( MSISession *session, const uint8_t *reason ); 229int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason );
221 230
222 231
223/** 232/**
224 * @brief Terminate the current call. 233 * @brief Terminate the current call.
225 * 234 *
226 * @param session Control session. 235 * @param session Control session.
236 * @param call_index To which call is this action handled.
227 * @return int 237 * @return int
228 */ 238 */
229int msi_stopcall ( MSISession *session ); 239int msi_stopcall ( MSISession *session, uint32_t call_index );
230 240
231#endif /* __TOXMSI */ 241#endif /* __TOXMSI */
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 4cdc38ba..f1ff2312 100755
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -29,6 +29,8 @@
29#include "media.h" 29#include "media.h"
30#include "msi.h" 30#include "msi.h"
31 31
32#include "../toxcore/logger.h"
33
32#include <stdlib.h> 34#include <stdlib.h>
33#include <string.h> 35#include <string.h>
34#include <assert.h> 36#include <assert.h>
@@ -43,6 +45,9 @@
43 45
44static const uint8_t audio_index = 0, video_index = 1; 46static const uint8_t audio_index = 0, video_index = 1;
45 47
48typedef struct _CallRTPSessions {
49 RTPSession *crtps[2]; /* Audio is first and video is second */
50} CallRTPSessions;
46 51
47typedef enum { 52typedef enum {
48 ts_closing, 53 ts_closing,
@@ -56,13 +61,27 @@ struct _ToxAv {
56 61
57 MSISession *msi_session; /** Main msi session */ 62 MSISession *msi_session; /** Main msi session */
58 63
59 RTPSession *rtp_sessions[2]; /* Audio is first and video is second */ 64 CallRTPSessions* rtp_sessions;
60 65
61 struct jitter_buffer *j_buf; 66 struct jitter_buffer *j_buf;
62 CodecState *cs; 67 CodecState *cs;
63 68
69 uint32_t max_calls;
70};
71
72const ToxAvCodecSettings av_DefaultSettings = {
73 1000000,
74 800,
75 600,
76
77 64000,
78 20,
79 48000,
80 1,
81 20
64}; 82};
65 83
84
66/** 85/**
67 * @brief Start new A/V session. There can only be one session at the time. If you register more 86 * @brief Start new A/V session. There can only be one session at the time. If you register more
68 * it will result in undefined behaviour. 87 * it will result in undefined behaviour.
@@ -74,7 +93,7 @@ struct _ToxAv {
74 * @return ToxAv* 93 * @return ToxAv*
75 * @retval NULL On error. 94 * @retval NULL On error.
76 */ 95 */
77ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) 96ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls)
78{ 97{
79 ToxAv *av = calloc ( sizeof(ToxAv), 1); 98 ToxAv *av = calloc ( sizeof(ToxAv), 1);
80 99
@@ -83,12 +102,12 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings)
83 102
84 av->messenger = (Messenger *)messenger; 103 av->messenger = (Messenger *)messenger;
85 104
86 av->msi_session = msi_init_session(av->messenger); 105 av->msi_session = msi_init_session(av->messenger, max_calls);
87 av->msi_session->agent_handler = av; 106 av->msi_session->agent_handler = av;
88 107
89 av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; 108 av->rtp_sessions = calloc(sizeof(RTPSession), max_calls);
90 109 av->max_calls = max_calls;
91 /* NOTE: This should be user defined or? */ 110
92 av->j_buf = create_queue(codec_settings->jbuf_capacity); 111 av->j_buf = create_queue(codec_settings->jbuf_capacity);
93 112
94 av->cs = codec_init_session(codec_settings->audio_bitrate, 113 av->cs = codec_init_session(codec_settings->audio_bitrate,
@@ -98,7 +117,7 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings)
98 codec_settings->video_width, 117 codec_settings->video_width,
99 codec_settings->video_height, 118 codec_settings->video_height,
100 codec_settings->video_bitrate); 119 codec_settings->video_bitrate);
101 120
102 return av; 121 return av;
103} 122}
104 123
@@ -111,14 +130,19 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings)
111void toxav_kill ( ToxAv *av ) 130void toxav_kill ( ToxAv *av )
112{ 131{
113 msi_terminate_session(av->msi_session); 132 msi_terminate_session(av->msi_session);
114 133
115 if ( av->rtp_sessions[audio_index] ) { 134 int i = 0;
116 rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle); 135 for (; i < av->max_calls; i ++) {
117 } 136 if ( av->rtp_sessions[i].crtps[audio_index] ) {
118 137 rtp_terminate_session(av->rtp_sessions[i].crtps[audio_index], av->msi_session->messenger_handle);
119 if ( av->rtp_sessions[video_index] ) { 138 }
120 rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle); 139
140 if ( av->rtp_sessions[i].crtps[video_index] ) {
141 rtp_terminate_session(av->rtp_sessions[i].crtps[video_index], av->msi_session->messenger_handle);
142 }
121 } 143 }
144
145 free(av->rtp_sessions);
122 146
123 codec_terminate_session(av->cs); 147 codec_terminate_session(av->cs);
124 148
@@ -148,13 +172,9 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
148 * @retval 0 Success. 172 * @retval 0 Success.
149 * @retval ToxAvError On error. 173 * @retval ToxAvError On error.
150 */ 174 */
151int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds ) 175int toxav_call (ToxAv* av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds )
152{ 176{
153 if ( av->msi_session->call ) { 177 return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user);
154 return ErrorAlreadyInCall;
155 }
156
157 return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
158} 178}
159 179
160/** 180/**
@@ -165,17 +185,17 @@ int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_second
165 * @retval 0 Success. 185 * @retval 0 Success.
166 * @retval ToxAvError On error. 186 * @retval ToxAvError On error.
167 */ 187 */
168int toxav_hangup ( ToxAv *av ) 188int toxav_hangup ( ToxAv* av, uint32_t call_index )
169{ 189{
170 if ( !av->msi_session->call ) { 190 if ( !av->msi_session->calls[call_index] ) {
171 return ErrorNoCall; 191 return ErrorNoCall;
172 } 192 }
173 193
174 if ( av->msi_session->call->state != call_active ) { 194 if ( av->msi_session->calls[call_index]->state != call_active ) {
175 return ErrorInvalidState; 195 return ErrorInvalidState;
176 } 196 }
177 197
178 return msi_hangup(av->msi_session); 198 return msi_hangup(av->msi_session, call_index);
179} 199}
180 200
181/** 201/**
@@ -187,17 +207,17 @@ int toxav_hangup ( ToxAv *av )
187 * @retval 0 Success. 207 * @retval 0 Success.
188 * @retval ToxAvError On error. 208 * @retval ToxAvError On error.
189 */ 209 */
190int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) 210int toxav_answer ( ToxAv* av, uint32_t call_index, ToxAvCallType call_type )
191{ 211{
192 if ( !av->msi_session->call ) { 212 if ( !av->msi_session->calls[call_index] ) {
193 return ErrorNoCall; 213 return ErrorNoCall;
194 } 214 }
195 215
196 if ( av->msi_session->call->state != call_starting ) { 216 if ( av->msi_session->calls[call_index]->state != call_starting ) {
197 return ErrorInvalidState; 217 return ErrorInvalidState;
198 } 218 }
199 219
200 return msi_answer(av->msi_session, call_type); 220 return msi_answer(av->msi_session, call_index, call_type);
201} 221}
202 222
203/** 223/**
@@ -209,17 +229,17 @@ int toxav_answer ( ToxAv *av, ToxAvCallType call_type )
209 * @retval 0 Success. 229 * @retval 0 Success.
210 * @retval ToxAvError On error. 230 * @retval ToxAvError On error.
211 */ 231 */
212int toxav_reject ( ToxAv *av, const char *reason ) 232int toxav_reject ( ToxAv* av, uint32_t call_index, const char* reason )
213{ 233{
214 if ( !av->msi_session->call ) { 234 if ( !av->msi_session->calls[call_index] ) {
215 return ErrorNoCall; 235 return ErrorNoCall;
216 } 236 }
217 237
218 if ( av->msi_session->call->state != call_starting ) { 238 if ( av->msi_session->calls[call_index]->state != call_starting ) {
219 return ErrorInvalidState; 239 return ErrorInvalidState;
220 } 240 }
221 241
222 return msi_reject(av->msi_session, (const uint8_t *) reason); 242 return msi_reject(av->msi_session, call_index, (const uint8_t *) reason);
223} 243}
224 244
225/** 245/**
@@ -232,13 +252,13 @@ int toxav_reject ( ToxAv *av, const char *reason )
232 * @retval 0 Success. 252 * @retval 0 Success.
233 * @retval ToxAvError On error. 253 * @retval ToxAvError On error.
234 */ 254 */
235int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) 255int toxav_cancel ( ToxAv* av, uint32_t call_index, int peer_id, const char* reason )
236{ 256{
237 if ( !av->msi_session->call ) { 257 if ( !av->msi_session->calls[call_index] ) {
238 return ErrorNoCall; 258 return ErrorNoCall;
239 } 259 }
240 260
241 return msi_cancel(av->msi_session, peer_id, reason); 261 return msi_cancel(av->msi_session, call_index, peer_id, reason);
242} 262}
243 263
244/** 264/**
@@ -249,13 +269,13 @@ int toxav_cancel ( ToxAv *av, int peer_id, const char *reason )
249 * @retval 0 Success. 269 * @retval 0 Success.
250 * @retval ToxAvError On error. 270 * @retval ToxAvError On error.
251 */ 271 */
252int toxav_stop_call ( ToxAv *av ) 272int toxav_stop_call ( ToxAv* av, uint32_t call_index )
253{ 273{
254 if ( !av->msi_session->call ) { 274 if ( !av->msi_session->calls[call_index] ) {
255 return ErrorNoCall; 275 return ErrorNoCall;
256 } 276 }
257 277
258 return msi_stopcall(av->msi_session); 278 return msi_stopcall(av->msi_session, call_index);
259} 279}
260 280
261/** 281/**
@@ -266,43 +286,43 @@ int toxav_stop_call ( ToxAv *av )
266 * @retval 0 Success. 286 * @retval 0 Success.
267 * @retval ToxAvError On error. 287 * @retval ToxAvError On error.
268 */ 288 */
269int toxav_prepare_transmission ( ToxAv* av, int support_video ) 289int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_video )
270{ 290{
271 assert(av->msi_session); 291 if ( !av->msi_session || !av->msi_session->calls[call_index] ) {
272
273 if ( !av->msi_session || !av->msi_session->call ) {
274 return ErrorNoCall; 292 return ErrorNoCall;
275 } 293 }
276 294
277 av->rtp_sessions[audio_index] = rtp_init_session( 295 av->rtp_sessions[call_index].crtps[audio_index] =
278 type_audio, 296 rtp_init_session(
279 av->messenger, 297 type_audio,
280 av->msi_session->call->peers[0], 298 av->messenger,
281 av->msi_session->call->key_peer, 299 av->msi_session->calls[call_index]->peers[0],
282 av->msi_session->call->key_local, 300 av->msi_session->calls[call_index]->key_peer,
283 av->msi_session->call->nonce_peer, 301 av->msi_session->calls[call_index]->key_local,
284 av->msi_session->call->nonce_local 302 av->msi_session->calls[call_index]->nonce_peer,
285 ); 303 av->msi_session->calls[call_index]->nonce_local
304 );
286 305
287 306
288 if ( !av->rtp_sessions[audio_index] ) { 307 if ( !av->rtp_sessions[call_index].crtps[audio_index] ) {
289 fprintf(stderr, "Error while starting audio RTP session!\n"); 308 fprintf(stderr, "Error while starting audio RTP session!\n");
290 return ErrorStartingAudioRtp; 309 return ErrorStartingAudioRtp;
291 } 310 }
292 311
293 if ( support_video ) { 312 if ( support_video ) {
294 av->rtp_sessions[video_index] = rtp_init_session ( 313 av->rtp_sessions[call_index].crtps[video_index] =
295 type_video, 314 rtp_init_session (
296 av->messenger, 315 type_video,
297 av->msi_session->call->peers[0], 316 av->messenger,
298 av->msi_session->call->key_peer, 317 av->msi_session->calls[call_index]->peers[0],
299 av->msi_session->call->key_local, 318 av->msi_session->calls[call_index]->key_peer,
300 av->msi_session->call->nonce_peer, 319 av->msi_session->calls[call_index]->key_local,
301 av->msi_session->call->nonce_local 320 av->msi_session->calls[call_index]->nonce_peer,
302 ); 321 av->msi_session->calls[call_index]->nonce_local
303 322 );
304 323
305 if ( !av->rtp_sessions[video_index] ) { 324
325 if ( !av->rtp_sessions[call_index].crtps[video_index] ) {
306 fprintf(stderr, "Error while starting video RTP session!\n"); 326 fprintf(stderr, "Error while starting video RTP session!\n");
307 return ErrorStartingVideoRtp; 327 return ErrorStartingVideoRtp;
308 } 328 }
@@ -318,20 +338,20 @@ int toxav_prepare_transmission ( ToxAv* av, int support_video )
318 * @retval 0 Success. 338 * @retval 0 Success.
319 * @retval ToxAvError On error. 339 * @retval ToxAvError On error.
320 */ 340 */
321int toxav_kill_transmission ( ToxAv *av ) 341int toxav_kill_transmission ( ToxAv *av, uint32_t call_index )
322{ 342{
323 if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) { 343 if ( av->rtp_sessions[call_index].crtps[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[audio_index], av->messenger) ) {
324 fprintf(stderr, "Error while terminating audio RTP session!\n"); 344 fprintf(stderr, "Error while terminating audio RTP session!\n");
325 return ErrorTerminatingAudioRtp; 345 return ErrorTerminatingAudioRtp;
326 } 346 }
327 347
328 if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) { 348 if ( av->rtp_sessions[call_index].crtps[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[video_index], av->messenger) ) {
329 fprintf(stderr, "Error while terminating video RTP session!\n"); 349 fprintf(stderr, "Error while terminating video RTP session!\n");
330 return ErrorTerminatingVideoRtp; 350 return ErrorTerminatingVideoRtp;
331 } 351 }
332 352
333 av->rtp_sessions[audio_index] = NULL; 353 av->rtp_sessions[call_index].crtps[audio_index] = NULL;
334 av->rtp_sessions[video_index] = NULL; 354 av->rtp_sessions[call_index].crtps[video_index] = NULL;
335 355
336 356
337 return ErrorNone; 357 return ErrorNone;
@@ -349,10 +369,10 @@ int toxav_kill_transmission ( ToxAv *av )
349 * @retval 0 Success. 369 * @retval 0 Success.
350 * @retval -1 Failure. 370 * @retval -1 Failure.
351 */ 371 */
352inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length ) 372inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length )
353{ 373{
354 if ( av->rtp_sessions[type - TypeAudio] ) 374 if ( av->rtp_sessions[call_index].crtps[type - TypeAudio] )
355 return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); 375 return rtp_send_msg ( av->rtp_sessions[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
356 else return -1; 376 else return -1;
357} 377}
358 378
@@ -366,18 +386,18 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8
366 * @retval ToxAvError On Error. 386 * @retval ToxAvError On Error.
367 * @retval >=0 Size of received payload. 387 * @retval >=0 Size of received payload.
368 */ 388 */
369inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest ) 389inline__ int toxav_recv_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, uint8_t *dest )
370{ 390{
371 if ( !dest ) return ErrorInternal; 391 if ( !dest ) return ErrorInternal;
372 392
373 if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession; 393 if ( !av->rtp_sessions[call_index].crtps[type - TypeAudio] ) return ErrorNoRtpSession;
374 394
375 RTPMessage *message; 395 RTPMessage *message;
376 396
377 if ( type == TypeAudio ) { 397 if ( type == TypeAudio ) {
378 398
379 do { 399 do {
380 message = rtp_recv_msg(av->rtp_sessions[audio_index]); 400 message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[audio_index]);
381 401
382 if (message) { 402 if (message) {
383 /* push the packet into the queue */ 403 /* push the packet into the queue */
@@ -390,7 +410,7 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de
390 410
391 if ( success == 2) return ErrorAudioPacketLost; 411 if ( success == 2) return ErrorAudioPacketLost;
392 } else { 412 } else {
393 message = rtp_recv_msg(av->rtp_sessions[video_index]); 413 message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[video_index]);
394 } 414 }
395 415
396 if ( message ) { 416 if ( message ) {
@@ -415,7 +435,7 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de
415 * @retval 0 Success. 435 * @retval 0 Success.
416 * @retval ToxAvError On Error. 436 * @retval ToxAvError On Error.
417 */ 437 */
418inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) 438inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **output)
419{ 439{
420 if ( !output ) return ErrorInternal; 440 if ( !output ) return ErrorInternal;
421 441
@@ -424,7 +444,7 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
424 int error; 444 int error;
425 445
426 do { 446 do {
427 recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); 447 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
428 448
429 if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) 449 if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK)
430 fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(error)); 450 fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(error));
@@ -450,7 +470,7 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
450 * @retval 0 Success. 470 * @retval 0 Success.
451 * @retval ToxAvError On error. 471 * @retval ToxAvError On error.
452 */ 472 */
453inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) 473inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, vpx_image_t *input)
454{ 474{
455 if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { 475 if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) {
456 fprintf(stderr, "Could not encode video frame\n"); 476 fprintf(stderr, "Could not encode video frame\n");
@@ -465,7 +485,7 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
465 485
466 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { 486 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) {
467 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 487 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
468 if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) 488 if (toxav_send_rtp_payload(av, call_index, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1)
469 ++sent; 489 ++sent;
470 } 490 }
471 } 491 }
@@ -488,13 +508,13 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
488 * @retval >=0 Size of received data in frames/samples. 508 * @retval >=0 Size of received data in frames/samples.
489 * @retval ToxAvError On error. 509 * @retval ToxAvError On error.
490 */ 510 */
491inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest ) 511inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, int16_t *dest )
492{ 512{
493 if ( !dest ) return ErrorInternal; 513 if ( !dest ) return ErrorInternal;
494 514
495 uint8_t packet [RTP_PAYLOAD_SIZE]; 515 uint8_t packet [RTP_PAYLOAD_SIZE];
496 516
497 int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); 517 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
498 518
499 if ( recved_size == ErrorAudioPacketLost ) { 519 if ( recved_size == ErrorAudioPacketLost ) {
500 return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 520 return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
@@ -516,7 +536,7 @@ inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
516 * @retval 0 Success. 536 * @retval 0 Success.
517 * @retval ToxAvError On error. 537 * @retval ToxAvError On error.
518 */ 538 */
519inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) 539inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const int16_t *frame, int frame_size)
520{ 540{
521 uint8_t temp_data[RTP_PAYLOAD_SIZE]; 541 uint8_t temp_data[RTP_PAYLOAD_SIZE];
522 int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data)); 542 int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data));
@@ -524,7 +544,7 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
524 if (ret <= 0) 544 if (ret <= 0)
525 return ErrorInternal; 545 return ErrorInternal;
526 546
527 return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); 547 return toxav_send_rtp_payload(av, call_index, TypeAudio, temp_data, ret);
528} 548}
529 549
530/** 550/**
@@ -536,14 +556,14 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
536 * @retval ToxAvCallType On success. 556 * @retval ToxAvCallType On success.
537 * @retval ToxAvError On error. 557 * @retval ToxAvError On error.
538 */ 558 */
539int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) 559int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer )
540{ 560{
541 assert(av->msi_session); 561 assert(av->msi_session);
542 562
543 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 563 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
544 return ErrorInternal; 564 return ErrorInternal;
545 565
546 return av->msi_session->call->type_peer[peer]; 566 return av->msi_session->calls[call_index]->type_peer[peer];
547} 567}
548 568
549/** 569/**
@@ -554,14 +574,14 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer )
554 * @return int 574 * @return int
555 * @retval ToxAvError No peer id 575 * @retval ToxAvError No peer id
556 */ 576 */
557int toxav_get_peer_id ( ToxAv* av, int peer ) 577int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer )
558{ 578{
559 assert(av->msi_session); 579 assert(av->msi_session);
560 580
561 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 581 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
562 return ErrorInternal; 582 return ErrorInternal;
563 583
564 return av->msi_session->call->peers[peer]; 584 return av->msi_session->calls[call_index]->peers[peer];
565} 585}
566 586
567/** 587/**
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 349e9498..89addb2b 100755
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -29,7 +29,7 @@
29/* vpx_image_t */ 29/* vpx_image_t */
30#include <vpx/vpx_image.h> 30#include <vpx/vpx_image.h>
31 31
32typedef void ( *ToxAVCallback ) ( void *arg ); 32typedef void ( *ToxAVCallback ) ( uint32_t, void *arg );
33typedef struct _ToxAv ToxAv; 33typedef struct _ToxAv ToxAv;
34 34
35#ifndef __TOX_DEFINED__ 35#ifndef __TOX_DEFINED__
@@ -119,17 +119,7 @@ typedef struct _ToxAvCodecSettings {
119 uint32_t jbuf_capacity; /* Size of jitter buffer */ 119 uint32_t jbuf_capacity; /* Size of jitter buffer */
120} ToxAvCodecSettings; 120} ToxAvCodecSettings;
121 121
122static const ToxAvCodecSettings av_DefaultSettings = { 122extern const ToxAvCodecSettings av_DefaultSettings;
123 1000000,
124 800,
125 600,
126
127 64000,
128 20,
129 48000,
130 1,
131 20
132};
133 123
134/** 124/**
135 * @brief Start new A/V session. There can only be one session at the time. If you register more 125 * @brief Start new A/V session. There can only be one session at the time. If you register more
@@ -142,7 +132,7 @@ static const ToxAvCodecSettings av_DefaultSettings = {
142 * @return ToxAv* 132 * @return ToxAv*
143 * @retval NULL On error. 133 * @retval NULL On error.
144 */ 134 */
145ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings); 135ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls);
146 136
147/** 137/**
148 * @brief Remove A/V session. 138 * @brief Remove A/V session.
@@ -172,7 +162,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID
172 * @retval 0 Success. 162 * @retval 0 Success.
173 * @retval ToxAvError On error. 163 * @retval ToxAvError On error.
174 */ 164 */
175int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds); 165int toxav_call(ToxAv *av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds);
176 166
177/** 167/**
178 * @brief Hangup active call. 168 * @brief Hangup active call.
@@ -182,7 +172,7 @@ int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds
182 * @retval 0 Success. 172 * @retval 0 Success.
183 * @retval ToxAvError On error. 173 * @retval ToxAvError On error.
184 */ 174 */
185int toxav_hangup(ToxAv *av); 175int toxav_hangup(ToxAv *av, uint32_t call_index);
186 176
187/** 177/**
188 * @brief Answer incomming call. 178 * @brief Answer incomming call.
@@ -193,7 +183,7 @@ int toxav_hangup(ToxAv *av);
193 * @retval 0 Success. 183 * @retval 0 Success.
194 * @retval ToxAvError On error. 184 * @retval ToxAvError On error.
195 */ 185 */
196int toxav_answer(ToxAv *av, ToxAvCallType call_type ); 186int toxav_answer(ToxAv *av, uint32_t call_index, ToxAvCallType call_type );
197 187
198/** 188/**
199 * @brief Reject incomming call. 189 * @brief Reject incomming call.
@@ -204,7 +194,7 @@ int toxav_answer(ToxAv *av, ToxAvCallType call_type );
204 * @retval 0 Success. 194 * @retval 0 Success.
205 * @retval ToxAvError On error. 195 * @retval ToxAvError On error.
206 */ 196 */
207int toxav_reject(ToxAv *av, const char *reason); 197int toxav_reject(ToxAv *av, uint32_t call_index, const char *reason);
208 198
209/** 199/**
210 * @brief Cancel outgoing request. 200 * @brief Cancel outgoing request.
@@ -216,7 +206,7 @@ int toxav_reject(ToxAv *av, const char *reason);
216 * @retval 0 Success. 206 * @retval 0 Success.
217 * @retval ToxAvError On error. 207 * @retval ToxAvError On error.
218 */ 208 */
219int toxav_cancel(ToxAv* av, int peer_id, const char* reason); 209int toxav_cancel(ToxAv* av, uint32_t call_index, int peer_id, const char* reason);
220 210
221/** 211/**
222 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 212 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
@@ -226,7 +216,7 @@ int toxav_cancel(ToxAv* av, int peer_id, const char* reason);
226 * @retval 0 Success. 216 * @retval 0 Success.
227 * @retval ToxAvError On error. 217 * @retval ToxAvError On error.
228 */ 218 */
229int toxav_stop_call(ToxAv *av); 219int toxav_stop_call(ToxAv *av, uint32_t call_index);
230 220
231/** 221/**
232 * @brief Must be call before any RTP transmission occurs. 222 * @brief Must be call before any RTP transmission occurs.
@@ -237,7 +227,7 @@ int toxav_stop_call(ToxAv *av);
237 * @retval 0 Success. 227 * @retval 0 Success.
238 * @retval ToxAvError On error. 228 * @retval ToxAvError On error.
239 */ 229 */
240int toxav_prepare_transmission(ToxAv *av, int support_video); 230int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, int support_video);
241 231
242/** 232/**
243 * @brief Call this at the end of the transmission. 233 * @brief Call this at the end of the transmission.
@@ -247,7 +237,7 @@ int toxav_prepare_transmission(ToxAv *av, int support_video);
247 * @retval 0 Success. 237 * @retval 0 Success.
248 * @retval ToxAvError On error. 238 * @retval ToxAvError On error.
249 */ 239 */
250int toxav_kill_transmission(ToxAv *av); 240int toxav_kill_transmission(ToxAv *av, uint32_t call_index);
251 241
252/** 242/**
253 * @brief Receive decoded video packet. 243 * @brief Receive decoded video packet.
@@ -258,7 +248,7 @@ int toxav_kill_transmission(ToxAv *av);
258 * @retval 0 Success. 248 * @retval 0 Success.
259 * @retval ToxAvError On Error. 249 * @retval ToxAvError On Error.
260 */ 250 */
261int toxav_recv_video ( ToxAv *av, vpx_image_t **output); 251int toxav_recv_video ( ToxAv* av, uint32_t call_index, vpx_image_t** output);
262 252
263/** 253/**
264 * @brief Receive decoded audio frame. 254 * @brief Receive decoded audio frame.
@@ -272,7 +262,7 @@ int toxav_recv_video ( ToxAv *av, vpx_image_t **output);
272 * @retval >=0 Size of received data in frames/samples. 262 * @retval >=0 Size of received data in frames/samples.
273 * @retval ToxAvError On error. 263 * @retval ToxAvError On error.
274 */ 264 */
275int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); 265int toxav_recv_audio( ToxAv* av, uint32_t call_index, int frame_size, int16_t* dest );
276 266
277/** 267/**
278 * @brief Encode and send video packet. 268 * @brief Encode and send video packet.
@@ -283,7 +273,7 @@ int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest );
283 * @retval 0 Success. 273 * @retval 0 Success.
284 * @retval ToxAvError On error. 274 * @retval ToxAvError On error.
285 */ 275 */
286int toxav_send_video ( ToxAv *av, vpx_image_t *input); 276int toxav_send_video ( ToxAv* av, uint32_t call_index, vpx_image_t* input);
287 277
288/** 278/**
289 * @brief Encode and send audio frame. 279 * @brief Encode and send audio frame.
@@ -296,7 +286,7 @@ int toxav_send_video ( ToxAv *av, vpx_image_t *input);
296 * @retval 0 Success. 286 * @retval 0 Success.
297 * @retval ToxAvError On error. 287 * @retval ToxAvError On error.
298 */ 288 */
299int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size); 289int toxav_send_audio ( ToxAv* av, uint32_t call_index, const int16_t* frame, int frame_size);
300 290
301/** 291/**
302 * @brief Get peer transmission type. It can either be audio or video. 292 * @brief Get peer transmission type. It can either be audio or video.
@@ -307,7 +297,7 @@ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
307 * @retval ToxAvCallType On success. 297 * @retval ToxAvCallType On success.
308 * @retval ToxAvError On error. 298 * @retval ToxAvError On error.
309 */ 299 */
310int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); 300int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer );
311 301
312/** 302/**
313 * @brief Get id of peer participating in conversation 303 * @brief Get id of peer participating in conversation
@@ -317,7 +307,7 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer );
317 * @return int 307 * @return int
318 * @retval ToxAvError No peer id 308 * @retval ToxAvError No peer id
319 */ 309 */
320int toxav_get_peer_id ( ToxAv* av, int peer ); 310int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer );
321 311
322/** 312/**
323 * @brief Is certain capability supported 313 * @brief Is certain capability supported
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index 1089e2ff..870e6ca2 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -27,6 +27,8 @@
27#include "config.h" 27#include "config.h"
28#endif 28#endif
29 29
30#include "logger.h"
31
30#include "DHT.h" 32#include "DHT.h"
31 33
32#ifdef ENABLE_ASSOC_DHT 34#ifdef ENABLE_ASSOC_DHT
@@ -198,18 +200,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
198 /* Refresh the client timestamp. */ 200 /* Refresh the client timestamp. */
199 if (ip_port.ip.family == AF_INET) { 201 if (ip_port.ip.family == AF_INET) {
200 202
201#ifdef LOGGING 203 LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
202 204 LOGGER_INFO("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i,
203 if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { 205 ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port),
204 size_t x; 206 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
205 x = sprintf(logbuffer, "coipil[%u]: switching ipv4 from %s:%u ", i, 207 }
206 ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port)); 208 );
207 sprintf(logbuffer + x, "to %s:%u\n",
208 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
209 loglog(logbuffer);
210 }
211
212#endif
213 209
214 if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) 210 if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
215 return 1; 211 return 1;
@@ -217,19 +213,13 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
217 list[i].assoc4.ip_port = ip_port; 213 list[i].assoc4.ip_port = ip_port;
218 list[i].assoc4.timestamp = temp_time; 214 list[i].assoc4.timestamp = temp_time;
219 } else if (ip_port.ip.family == AF_INET6) { 215 } else if (ip_port.ip.family == AF_INET6) {
220 216
221#ifdef LOGGING 217 LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {
222 218 LOGGER_INFO("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i,
223 if (!ipport_equal(&list[i].assoc6.ip_port, &ip_port)) { 219 ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port),
224 size_t x; 220 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
225 x = sprintf(logbuffer, "coipil[%u]: switching ipv6 from %s:%u ", i, 221 }
226 ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port)); 222 );
227 sprintf(logbuffer + x, "to %s:%u\n",
228 ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
229 loglog(logbuffer);
230 }
231
232#endif
233 223
234 if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) 224 if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)
235 return 1; 225 return 1;
@@ -251,10 +241,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
251 /* Initialize client timestamp. */ 241 /* Initialize client timestamp. */
252 list[i].assoc4.timestamp = temp_time; 242 list[i].assoc4.timestamp = temp_time;
253 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 243 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
254#ifdef LOGGING 244
255 sprintf(logbuffer, "coipil[%u]: switching client_id (ipv4) \n", i); 245 LOGGER_DEBUG("coipil[%u]: switching client_id (ipv4)", i);
256 loglog(logbuffer); 246
257#endif
258 /* kill the other address, if it was set */ 247 /* kill the other address, if it was set */
259 memset(&list[i].assoc6, 0, sizeof(list[i].assoc6)); 248 memset(&list[i].assoc6, 0, sizeof(list[i].assoc6));
260 return 1; 249 return 1;
@@ -262,10 +251,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
262 /* Initialize client timestamp. */ 251 /* Initialize client timestamp. */
263 list[i].assoc6.timestamp = temp_time; 252 list[i].assoc6.timestamp = temp_time;
264 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 253 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
265#ifdef LOGGING 254
266 sprintf(logbuffer, "coipil[%u]: switching client_id (ipv6) \n", i); 255 LOGGER_DEBUG("coipil[%u]: switching client_id (ipv6)", i);
267 loglog(logbuffer); 256
268#endif
269 /* kill the other address, if it was set */ 257 /* kill the other address, if it was set */
270 memset(&list[i].assoc4, 0, sizeof(list[i].assoc4)); 258 memset(&list[i].assoc4, 0, sizeof(list[i].assoc4));
271 return 1; 259 return 1;
@@ -469,18 +457,11 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa
469 uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request); 457 uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);
470 458
471 if (!num_found) { 459 if (!num_found) {
472#ifdef LOGGING 460 LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned zero nodes");
473 loglog("get_close_nodes(): Assoc_get_close_entries() returned zero nodes.\n");
474#endif
475
476 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good); 461 return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
477 } 462 }
478 463
479#ifdef LOGGING 464 LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes", request.count_good, num_found - request.count_good);
480 sprintf(logbuffer, "get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes.\n",
481 request.count_good, num_found - request.count_good);
482 loglog(logbuffer);
483#endif
484 465
485 uint8_t i, num_returned = 0; 466 uint8_t i, num_returned = 0;
486 467
diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc
index 5e529267..5f9ab0d7 100644
--- a/toxcore/Makefile.inc
+++ b/toxcore/Makefile.inc
@@ -31,6 +31,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
31 ../toxcore/assoc.c \ 31 ../toxcore/assoc.c \
32 ../toxcore/onion.h \ 32 ../toxcore/onion.h \
33 ../toxcore/onion.c \ 33 ../toxcore/onion.c \
34 ../toxcore/logger.h \
35 ../toxcore/logger.c \
34 ../toxcore/onion_announce.h \ 36 ../toxcore/onion_announce.h \
35 ../toxcore/onion_announce.c \ 37 ../toxcore/onion_announce.c \
36 ../toxcore/onion_client.h \ 38 ../toxcore/onion_client.h \
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index db5390c0..2033e6a9 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -25,6 +25,7 @@
25#include "config.h" 25#include "config.h"
26#endif 26#endif
27 27
28#include "logger.h"
28#include "Messenger.h" 29#include "Messenger.h"
29#include "assoc.h" 30#include "assoc.h"
30#include "network.h" 31#include "network.h"
@@ -2245,7 +2246,7 @@ void do_messenger(Messenger *m)
2245#ifdef LOGGING 2246#ifdef LOGGING
2246 2247
2247 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { 2248 if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {
2248 loglog(" = = = = = = = = \n"); 2249
2249#ifdef ENABLE_ASSOC_DHT 2250#ifdef ENABLE_ASSOC_DHT
2250 Assoc_status(m->dht->assoc); 2251 Assoc_status(m->dht->assoc);
2251#endif 2252#endif
@@ -2254,12 +2255,10 @@ void do_messenger(Messenger *m)
2254 size_t c; 2255 size_t c;
2255 2256
2256 for (c = 0; c < m->numchats; c++) { 2257 for (c = 0; c < m->numchats; c++) {
2257 loglog("---------------- \n");
2258 Assoc_status(m->chats[c]->assoc); 2258 Assoc_status(m->chats[c]->assoc);
2259 } 2259 }
2260 } 2260 }
2261 2261
2262 loglog(" = = = = = = = = \n");
2263 2262
2264 lastdump = unix_time(); 2263 lastdump = unix_time();
2265 uint32_t client, last_pinged; 2264 uint32_t client, last_pinged;
@@ -2276,14 +2275,12 @@ void do_messenger(Messenger *m)
2276 if (last_pinged > 999) 2275 if (last_pinged > 999)
2277 last_pinged = 999; 2276 last_pinged = 999;
2278 2277
2279 snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n", 2278 LOGGER_DEBUG("C[%2u] %s:%u [%3u] %s",
2280 client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), 2279 client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),
2281 last_pinged, ID2String(cptr->client_id)); 2280 last_pinged, ID2String(cptr->client_id));
2282 loglog(logbuffer);
2283 } 2281 }
2284 } 2282 }
2285 2283
2286 loglog(" = = = = = = = = \n");
2287 2284
2288 uint32_t friend, dhtfriend; 2285 uint32_t friend, dhtfriend;
2289 2286
@@ -2311,9 +2308,7 @@ void do_messenger(Messenger *m)
2311 dht2m[m2dht[friend]] = friend; 2308 dht2m[m2dht[friend]] = friend;
2312 2309
2313 if (m->numfriends != m->dht->num_friends) { 2310 if (m->numfriends != m->dht->num_friends) {
2314 sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n", 2311 LOGGER_DEBUG("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends);
2315 m->dht->num_friends, m->numfriends);
2316 loglog(logbuffer);
2317 } 2312 }
2318 2313
2319 uint32_t ping_lastrecv; 2314 uint32_t ping_lastrecv;
@@ -2334,14 +2329,11 @@ void do_messenger(Messenger *m)
2334 if (ping_lastrecv > 999) 2329 if (ping_lastrecv > 999)
2335 ping_lastrecv = 999; 2330 ping_lastrecv = 999;
2336 2331
2337 snprintf(logbuffer, sizeof(logbuffer), "F[%2u:%2u] <%s> %02i [%03u] %s\n", 2332 LOGGER_DEBUG("F[%2u:%2u] <%s> %02i [%03u] %s",
2338 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, 2333 dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id,
2339 ping_lastrecv, ID2String(msgfptr->client_id)); 2334 ping_lastrecv, ID2String(msgfptr->client_id));
2340 loglog(logbuffer);
2341 } else { 2335 } else {
2342 snprintf(logbuffer, sizeof(logbuffer), "F[--:%2u] %s\n", 2336 LOGGER_DEBUG("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id));
2343 friend, ID2String(dhtfptr->client_id));
2344 loglog(logbuffer);
2345 } 2337 }
2346 2338
2347 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { 2339 for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {
@@ -2355,20 +2347,16 @@ void do_messenger(Messenger *m)
2355 2347
2356 if (last_pinged > 999) 2348 if (last_pinged > 999)
2357 last_pinged = 999; 2349 last_pinged = 999;
2358 2350
2359 snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n", 2351 LOGGER_DEBUG("F[%2u] => C[%2u] %s:%u [%3u] %s",
2360 friend, client, ip_ntoa(&assoc->ip_port.ip), 2352 friend, client, ip_ntoa(&assoc->ip_port.ip),
2361 ntohs(assoc->ip_port.port), last_pinged, 2353 ntohs(assoc->ip_port.port), last_pinged,
2362 ID2String(cptr->client_id)); 2354 ID2String(cptr->client_id));
2363 loglog(logbuffer);
2364 } 2355 }
2365 } 2356 }
2366 } 2357 }
2367
2368 loglog(" = = = = = = = = \n");
2369 } 2358 }
2370 2359#endif /* LOGGING */
2371#endif
2372} 2360}
2373 2361
2374/* 2362/*
diff --git a/toxcore/assoc.c b/toxcore/assoc.c
index 2c1f0bad..c8f58c9c 100644
--- a/toxcore/assoc.c
+++ b/toxcore/assoc.c
@@ -3,6 +3,7 @@
3#include "config.h" 3#include "config.h"
4#endif 4#endif
5 5
6#include "logger.h"
6#include "DHT.h" 7#include "DHT.h"
7#include "assoc.h" 8#include "assoc.h"
8#include "ping.h" 9#include "ping.h"
@@ -524,9 +525,7 @@ static void client_id_self_update(Assoc *assoc)
524 assoc->self_hash = id_hash(assoc, assoc->self_client_id); 525 assoc->self_hash = id_hash(assoc, assoc->self_client_id);
525 } 526 }
526 527
527#ifdef LOGGING 528 LOGGER_DEBUG("id is now set, purging cache of self-references");
528 loglog("assoc: id is now set, purging cache of self-references...\n");
529#endif
530 529
531 /* if we already added some (or loaded some) entries, 530 /* if we already added some (or loaded some) entries,
532 * look and remove if we find a match 531 * look and remove if we find a match
@@ -821,10 +820,8 @@ Assoc *new_Assoc(size_t bits, size_t entries, uint8_t *public_id)
821 entries_test = prime_upto_min9(entries_test - 1); 820 entries_test = prime_upto_min9(entries_test - 1);
822 821
823 if (entries_test != entries) { 822 if (entries_test != entries) {
824#ifdef LOGGING 823
825 sprintf(logbuffer, "new_Assoc(): trimmed %i to %i.\n", (int)entries, (int)entries_test); 824 LOGGER_DEBUG("trimmed %i to %i.\n", (int)entries, (int)entries_test);
826 loglog(logbuffer);
827#endif
828 entries = (size_t)entries_test; 825 entries = (size_t)entries_test;
829 } 826 }
830 } 827 }
@@ -873,7 +870,7 @@ void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *id)
873 870
874#ifdef LOGGING 871#ifdef LOGGING
875static char *idpart2str(uint8_t *id, size_t len); 872static char *idpart2str(uint8_t *id, size_t len);
876#endif 873#endif /* LOGGING */
877 874
878/* refresh buckets */ 875/* refresh buckets */
879void do_Assoc(Assoc *assoc, DHT *dht) 876void do_Assoc(Assoc *assoc, DHT *dht)
@@ -929,53 +926,30 @@ void do_Assoc(Assoc *assoc, DHT *dht)
929 break; 926 break;
930 } 927 }
931 928
932#ifdef LOGGING
933 size_t total = 0, written = sprintf(logbuffer, "assoc: [%u] => ",
934 (uint32_t)(candidate % assoc->candidates_bucket_count));
935
936 if (written > 0)
937 total += written;
938
939#endif
940
941 if (seen) { 929 if (seen) {
942 IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6; 930 IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6;
943#ifdef LOGGING 931
944 written = sprintf(logbuffer + total, " S[%s...] %s:%u", idpart2str(seen->client.client_id, 8), 932 LOGGER_DEBUG("[%u] => S[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
945 ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port)); 933 idpart2str(seen->client.client_id, 8), ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));
946 934
947 if (written > 0)
948 total += written;
949
950#endif
951 DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id); 935 DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id);
952 seen->getnodes = unix_time(); 936 seen->getnodes = unix_time();
953 } 937 }
954 938
955 if (heard && (heard != seen)) { 939 if (heard && (heard != seen)) {
956 IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6; 940 IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6;
957#ifdef LOGGING 941
958 written = sprintf(logbuffer + total, " H[%s...] %s:%u", idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), 942 LOGGER_DEBUG("[%u] => H[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count),
959 htons(ipp->port)); 943 idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), htons(ipp->port));
960 944
961 if (written > 0)
962 total += written;
963
964#endif
965 DHT_getnodes(dht, ipp, heard->client.client_id, target_id); 945 DHT_getnodes(dht, ipp, heard->client.client_id, target_id);
966 heard->getnodes = unix_time(); 946 heard->getnodes = unix_time();
967 } 947 }
968 948
969#ifdef LOGGING 949 LOGGER_SCOPE (
970 950 if ( !heard && !seen )
971 if (!heard && !seen) 951 LOGGER_DEBUG("[%u] => no nodes to talk to??", (uint32_t)(candidate % assoc->candidates_bucket_count));
972 sprintf(logbuffer + total, "no nodes to talk to??\n"); 952 );
973 else
974 /* for arcane reasons, sprintf(str, "\n") doesn't function */
975 sprintf(logbuffer + total, "%s", "\n");
976
977 loglog(logbuffer);
978#endif
979 } 953 }
980} 954}
981 955
@@ -1009,11 +983,11 @@ static char *idpart2str(uint8_t *id, size_t len)
1009void Assoc_status(Assoc *assoc) 983void Assoc_status(Assoc *assoc)
1010{ 984{
1011 if (!assoc) { 985 if (!assoc) {
1012 loglog("Assoc status: no assoc\n"); 986 LOGGER_INFO("Assoc status: no assoc");
1013 return; 987 return;
1014 } 988 }
1015 989
1016 loglog("[b:p] hash => [id...] used, seen, heard\n"); 990 LOGGER_INFO("[b:p] hash => [id...] used, seen, heard");
1017 991
1018 size_t bid, cid, total = 0; 992 size_t bid, cid, total = 0;
1019 993
@@ -1024,24 +998,23 @@ void Assoc_status(Assoc *assoc)
1024 Client_entry *entry = &bucket->list[cid]; 998 Client_entry *entry = &bucket->list[cid];
1025 999
1026 if (entry->hash) { 1000 if (entry->hash) {
1027 sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n", 1001 total++;
1028 (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8), 1002
1029 entry->used_at ? (int)(unix_time() - entry->used_at) : 0, 1003 LOGGER_INFO("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n",
1030 entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0, 1004 (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8),
1031 entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?', 1005 entry->used_at ? (int)(unix_time() - entry->used_at) : 0,
1006 entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,
1007 entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',
1032 entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0, 1008 entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,
1033 entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?'); 1009 entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');
1034 loglog(logbuffer);
1035 total++;
1036 } 1010 }
1037 } 1011 }
1038 } 1012 }
1039 1013
1040 if (total) { 1014 if (total) {
1041 sprintf(logbuffer, "Total: %i entries, table usage %i%%.\n", (int)total, 1015 LOGGER_INFO("Total: %i entries, table usage %i%%.\n", (int)total,
1042 (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); 1016 (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));
1043 loglog(logbuffer);
1044 } 1017 }
1045} 1018}
1046 1019
1047#endif 1020#endif /* LOGGING */
diff --git a/toxcore/assoc.h b/toxcore/assoc.h
index 9dbc75f2..0fdff4fe 100644
--- a/toxcore/assoc.h
+++ b/toxcore/assoc.h
@@ -98,6 +98,6 @@ void kill_Assoc(Assoc *assoc);
98 98
99#ifdef LOGGING 99#ifdef LOGGING
100void Assoc_status(Assoc *assoc); 100void Assoc_status(Assoc *assoc);
101#endif 101#endif /* LOGGING */
102 102
103#endif /* !__ASSOC_H__ */ 103#endif /* !__ASSOC_H__ */
diff --git a/toxcore/logger.c b/toxcore/logger.c
new file mode 100644
index 00000000..e700fe71
--- /dev/null
+++ b/toxcore/logger.c
@@ -0,0 +1,159 @@
1/* logger.c
2 *
3 * Wrapping logger functions in nice macros
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#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif /* HAVE_CONFIG_H */
27
28
29#include "logger.h"
30
31#ifdef LOGGING
32
33#include "network.h" /* for time */
34
35#include <stdio.h>
36#include <errno.h>
37#include <stdlib.h>
38#include <stdarg.h>
39#include <inttypes.h>
40#include <time.h>
41
42#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
43#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
44#endif
45
46static struct logger_config {
47 FILE* log_file;
48 LoggerLevel level;
49 uint64_t start_time; /* Time when lib loaded */
50}
51logger = {
52 NULL,
53 DEBUG,
54 0
55};
56
57void __attribute__((destructor)) terminate_logger()
58{
59 if ( !logger.log_file ) return;
60
61 time_t tim = time(NULL);
62
63 logger_write(ERROR, "============== Closing logger ==============\n"
64 "Time: %s", asctime(localtime(&tim)));
65
66 fclose(logger.log_file);
67}
68
69unsigned logger_get_pid()
70{
71 return
72 #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
73 GetCurrentProcessId();
74 #else
75 getpid();
76 #endif
77}
78
79const char* logger_stringify_level(LoggerLevel level)
80{
81 static const char* strings [] =
82 {
83 "INFO",
84 "DEBUG",
85 "WARNING",
86 "ERROR"
87 };
88
89 return strings[level];
90}
91
92
93int logger_init(const char* file_name, LoggerLevel level)
94{
95 char* final_l = calloc(sizeof(char), strlen(file_name) + 32);
96 sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid());
97
98 if ( logger.log_file ) {
99 fprintf(stderr, "Error opening logger name: %s with level %d: already opened!\n", final_l, level);
100 free (final_l);
101 return -1;
102 }
103
104 logger.log_file = fopen(final_l, "wb");
105
106 if ( logger.log_file == NULL ) {
107 char error[1000];
108 if ( strerror_r(errno, error, 1000) == 0 )
109 fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, error);
110 else
111 fprintf(stderr, "Error opening logger file: %s\n", final_l);
112
113 free (final_l);
114 return -1;
115 }
116
117
118 logger.level = level;
119 logger.start_time = current_time();
120
121
122 time_t tim = time(NULL);
123 logger_write(ERROR, "============== Starting logger ==============\n"
124 "Time: %s", asctime(localtime(&tim)));
125
126
127
128 free (final_l);
129 return 0;
130}
131
132
133void logger_write (LoggerLevel level, const char* format, ...)
134{
135 if (logger.log_file == NULL) {
136 /*fprintf(stderr, "Logger file is NULL!\n");*/
137 return;
138 }
139
140 if (logger.level > level) return; /* Don't print some levels xuh */
141
142 va_list _arg;
143 va_start (_arg, format);
144 vfprintf (logger.log_file, format, _arg);
145 va_end (_arg);
146
147 fflush(logger.log_file);
148}
149
150char* logger_timestr(char* dest)
151{
152 uint64_t diff = (current_time() - logger.start_time) / 1000; /* ms */
153 sprintf(dest, "%"PRIu64"", diff);
154
155 return dest;
156}
157
158
159#endif /* LOGGING */ \ No newline at end of file
diff --git a/toxcore/logger.h b/toxcore/logger.h
new file mode 100644
index 00000000..6c65850e
--- /dev/null
+++ b/toxcore/logger.h
@@ -0,0 +1,86 @@
1/* logger.h
2 *
3 * Wrapping logger functions in nice macros
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
25#ifndef __TOXLOGGER
26#define __TOXLOGGER
27
28// #define LOGGING
29
30#ifdef LOGGING
31#include <string.h>
32
33typedef enum _LoggerLevel
34{
35 INFO,
36 DEBUG,
37 WARNING,
38 ERROR
39} LoggerLevel;
40
41/*
42 * Set 'level' as the lowest printable level
43 */
44int logger_init(const char* file_name, LoggerLevel level);
45const char* logger_stringify_level(LoggerLevel level);
46unsigned logger_get_pid();
47void logger_write (LoggerLevel level, const char* format, ...);
48char* logger_timestr (char* dest);
49
50#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
51#define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
52#else
53#define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
54#endif
55
56#define WRITE_FORMAT(__LEVEL__, format) char* the_str = calloc(sizeof(char), strlen(format)+ 500); sprintf(the_str, "[%u] [%s] [%s] [%s:%d %s()] %s\n", \
57 logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__), _SFILE, __LINE__, __func__, format)
58
59/* Use these macros */
60
61#define LOGGER_INIT(name, level) logger_init(name, level);
62#define LOGGER_INFO(format, ...) do { char __time__[20]; WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
63#define LOGGER_DEBUG(format, ...) do { char __time__[20]; WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
64#define LOGGER_WARNING(format, ...) do { char __time__[20]; WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
65#define LOGGER_ERROR(format, ...) do { char __time__[20]; WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0)
66
67/* To do some checks or similar only when logging use this */
68#define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0)
69
70#else
71
72
73#define LOGGER_INIT(name, level)
74#define LOGGER_INFO(format, ...)
75#define LOGGER_DEBUG(format, ...)
76#define LOGGER_WARNING(format, ...)
77#define LOGGER_ERROR(format, ...)
78
79#define LOGGER_SCOPE(__SCOPE_DO__)
80
81#endif /* LOGGING */
82
83
84
85
86#endif /* __TOXLOGGER */ \ No newline at end of file
diff --git a/toxcore/network.c b/toxcore/network.c
index 47afab8e..7262f352 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -29,6 +29,9 @@
29#include "config.h" 29#include "config.h"
30#endif 30#endif
31 31
32#define LOGGING
33#include "logger.h"
34
32#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) 35#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
33#include <errno.h> 36#include <errno.h>
34#endif 37#endif
@@ -205,9 +208,32 @@ uint64_t random_64b(void)
205 return randnum; 208 return randnum;
206} 209}
207 210
208#ifdef LOGGING 211/* In case no logging */
209static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res); 212#ifndef LOGGING
210#endif 213
214#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__)
215
216#else
217
218#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0
219#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0
220
221#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \
222 (__ip_port__) .ip; \
223 if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \
224 LOGGER_INFO("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \
225 __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \
226 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
227 else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \
228 LOGGER_INFO("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \
229 __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \
230 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \
231 else /* empty or overwrite */ \
232 LOGGER_INFO("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \
233 __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \
234 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__));
235
236#endif /* LOGGING */
211 237
212/* Basic network functions: 238/* Basic network functions:
213 * Function to send packet(data) of length length to ip_port. 239 * Function to send packet(data) of length length to ip_port.
@@ -266,9 +292,9 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
266 } 292 }
267 293
268 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize); 294 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
269#ifdef LOGGING 295
270 loglogdata("O=>", data, length, &ip_port, res); 296 loglogdata("O=>", data, length, ip_port, res);
271#endif 297
272 298
273 if ((res >= 0) && ((uint32_t)res == length)) 299 if ((res >= 0) && ((uint32_t)res == length))
274 net->send_fail_eagain = 0; 300 net->send_fail_eagain = 0;
@@ -297,14 +323,10 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
297 int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); 323 int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
298 324
299 if (fail_or_len <= 0) { 325 if (fail_or_len <= 0) {
300#ifdef LOGGING 326
301 327 LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK))
302 if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) { 328 LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); );
303 sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); 329
304 loglog(logbuffer);
305 }
306
307#endif
308 return -1; /* Nothing received or empty packet. */ 330 return -1; /* Nothing received or empty packet. */
309 } 331 }
310 332
@@ -329,9 +351,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
329 } else 351 } else
330 return -1; 352 return -1;
331 353
332#ifdef LOGGING 354 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length);
333 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
334#endif
335 355
336 return 0; 356 return 0;
337} 357}
@@ -354,10 +374,7 @@ void networking_poll(Networking_Core *net)
354 if (length < 1) continue; 374 if (length < 1) continue;
355 375
356 if (!(net->packethandlers[data[0]].function)) { 376 if (!(net->packethandlers[data[0]].function)) {
357#ifdef LOGGING 377 LOGGER_WARNING("[%02u] -- Packet has no handler.\n", data[0]);
358 sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
359 loglog(logbuffer);
360#endif
361 continue; 378 continue;
362 } 379 }
363 380
@@ -460,22 +477,14 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds)
460 timeout.tv_usec = microseconds; 477 timeout.tv_usec = microseconds;
461 } 478 }
462 479
463#ifdef LOGGING
464 errno = 0;
465#endif
466 /* returns -1 on error, 0 on timeout, the socket on activity */ 480 /* returns -1 on error, 0 on timeout, the socket on activity */
467 int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr); 481 int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr);
468#ifdef LOGGING 482
469 483 LOGGER_SCOPE(
470 /* only dump if not timeout */ 484 if (res) LOGGER_INFO("select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno,
471 if (res) { 485 strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds),
472 sprintf(logbuffer, "select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno, 486 FD_ISSET(s->sock, &exceptfds));
473 strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds), 487 );
474 FD_ISSET(s->sock, &exceptfds));
475 loglog(logbuffer);
476 }
477
478#endif
479 488
480 if (FD_ISSET(s->sock, &writefds)) { 489 if (FD_ISSET(s->sock, &writefds)) {
481 s->send_fail_reset = 1; 490 s->send_fail_reset = 1;
@@ -628,20 +637,12 @@ Networking_Core *new_networking(IP ip, uint16_t port)
628 } 637 }
629 638
630 if (ip.family == AF_INET6) { 639 if (ip.family == AF_INET6) {
640
631#ifdef LOGGING 641#ifdef LOGGING
632 int is_dualstack = 642 int is_dualstack =
633#endif 643#endif /* LOGGING */
634 set_socket_dualstack(temp->sock); 644 set_socket_dualstack(temp->sock);
635#ifdef LOGGING 645 LOGGER_DEBUG( "Dual-stack socket: %s", is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses" );
636
637 if (is_dualstack) {
638 loglog("Dual-stack socket: enabled.\n");
639 } else {
640 loglog("Dual-stack socket: Failed to enable, won't be able to receive from/send to IPv4 addresses.\n");
641 }
642
643#endif
644
645 /* multicast local nodes */ 646 /* multicast local nodes */
646 struct ipv6_mreq mreq; 647 struct ipv6_mreq mreq;
647 memset(&mreq, 0, sizeof(mreq)); 648 memset(&mreq, 0, sizeof(mreq));
@@ -649,21 +650,13 @@ Networking_Core *new_networking(IP ip, uint16_t port)
649 mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; 650 mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
650 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; 651 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
651 mreq.ipv6mr_interface = 0; 652 mreq.ipv6mr_interface = 0;
653
652#ifdef LOGGING 654#ifdef LOGGING
653 errno = 0;
654 int res = 655 int res =
655#endif 656#endif /* LOGGING */
656 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); 657 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
657#ifdef LOGGING 658
658 659 LOGGER_DEBUG(res < 0 ? "Failed to activate local multicast membership. (%u, %s)" : "Local multicast group FF02::1 joined successfully", errno, strerror(errno) );
659 if (res < 0) {
660 sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
661 errno, strerror(errno));
662 loglog(logbuffer);
663 } else
664 loglog("Local multicast group FF02::1 joined successfully.\n");
665
666#endif
667 } 660 }
668 661
669 /* a hanging program or a different user might block the standard port; 662 /* a hanging program or a different user might block the standard port;
@@ -691,13 +684,9 @@ Networking_Core *new_networking(IP ip, uint16_t port)
691 684
692 if (!res) { 685 if (!res) {
693 temp->port = *portptr; 686 temp->port = *portptr;
694#ifdef LOGGING 687
695 loginit(temp->port); 688 LOGGER_DEBUG("Bound successfully to %s:%u", ip_ntoa(&ip), ntohs(temp->port));
696 689
697 sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
698 loglog(logbuffer);
699#endif
700
701 /* errno isn't reset on success, only set on failure, the failed 690 /* errno isn't reset on success, only set on failure, the failed
702 * binds with parallel clients yield a -EPERM to the outside if 691 * binds with parallel clients yield a -EPERM to the outside if
703 * errno isn't cleared here */ 692 * errno isn't cleared here */
@@ -1038,31 +1027,3 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
1038 1027
1039 return 1; 1028 return 1;
1040}; 1029};
1041
1042#ifdef LOGGING
1043static char errmsg_ok[3] = "OK";
1044static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
1045{
1046 uint16_t port = ntohs(ip_port->port);
1047 uint32_t data[2];
1048 data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0;
1049 data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0;
1050
1051 /* Windows doesn't necessarily know %zu */
1052 if (res < 0) {
1053 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\n",
1054 buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E',
1055 ip_ntoa(&ip_port->ip), port, errno, strerror(errno), data[0], data[1]);
1056 } else if ((res > 0) && ((size_t)res <= buflen))
1057 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x\n",
1058 buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='),
1059 ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
1060 else /* empty or overwrite */
1061 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x\n",
1062 buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen,
1063 ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]);
1064
1065 logbuffer[sizeof(logbuffer) - 1] = 0;
1066 loglog(logbuffer);
1067}
1068#endif
diff --git a/toxcore/tox.c b/toxcore/tox.c
index c07473dd..9b99174c 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "Messenger.h" 28#include "Messenger.h"
29#include "logger.h"
29 30
30#define __TOX_DEFINED__ 31#define __TOX_DEFINED__
31typedef struct Messenger Tox; 32typedef struct Messenger Tox;
@@ -773,6 +774,7 @@ int tox_isconnected(Tox *tox)
773 */ 774 */
774Tox *tox_new(uint8_t ipv6enabled) 775Tox *tox_new(uint8_t ipv6enabled)
775{ 776{
777 LOGGER_INIT(LOGGER_OUTPUT_FILE, LOGGER_LEVEL);
776 return new_messenger(ipv6enabled); 778 return new_messenger(ipv6enabled);
777} 779}
778 780
diff --git a/toxcore/util.c b/toxcore/util.c
index d56c446e..edc611ec 100644
--- a/toxcore/util.c
+++ b/toxcore/util.c
@@ -134,87 +134,3 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
134 134
135 return length == 0 ? 0 : -1; 135 return length == 0 ? 0 : -1;
136}; 136};
137
138#ifdef LOGGING
139time_t starttime = 0;
140size_t logbufferprelen = 0;
141char *logbufferpredata = NULL;
142char *logbufferprehead = NULL;
143char logbuffer[512];
144static FILE *logfile = NULL;
145void loginit(uint16_t port)
146{
147 if (logfile)
148 fclose(logfile);
149
150 if (!starttime) {
151 unix_time_update();
152 starttime = unix_time();
153 }
154
155 struct tm *tm = localtime(&starttime);
156
157 /* "%F %T" might not be Windows compatible */
158 if (strftime(logbuffer + 32, sizeof(logbuffer) - 32, "%F %T", tm))
159 sprintf(logbuffer, "%u-%s.log", ntohs(port), logbuffer + 32);
160 else
161 sprintf(logbuffer, "%u-%lu.log", ntohs(port), starttime);
162
163 logfile = fopen(logbuffer, "w");
164
165 if (logbufferpredata) {
166 if (logfile)
167 fprintf(logfile, "%s", logbufferpredata);
168
169 free(logbufferpredata);
170 logbufferpredata = NULL;
171 }
172
173};
174void loglog(char *text)
175{
176 if (logfile) {
177 fprintf(logfile, "%4u %s", (uint32_t)(unix_time() - starttime), text);
178 fflush(logfile);
179
180 return;
181 }
182
183 /* log messages before file was opened: store */
184
185 size_t len = strlen(text);
186
187 if (!starttime) {
188 unix_time_update();
189 starttime = unix_time();
190
191 logbufferprelen = 1024 + len - (len % 1024);
192 logbufferpredata = malloc(logbufferprelen);
193 logbufferprehead = logbufferpredata;
194 }
195
196 /* loginit() called meanwhile? (but failed to open) */
197 if (!logbufferpredata)
198 return;
199
200 if (len + (logbufferprehead - logbufferpredata) + 16U < logbufferprelen) {
201 size_t logpos = logbufferprehead - logbufferpredata;
202 size_t lennew = logbufferprelen * 1.4;
203 logbufferpredata = realloc(logbufferpredata, lennew);
204 logbufferprehead = logbufferpredata + logpos;
205 logbufferprelen = lennew;
206 }
207
208 int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(unix_time() - starttime), text);
209 logbufferprehead += written;
210}
211
212void logexit()
213{
214 if (logfile) {
215 fclose(logfile);
216 logfile = NULL;
217 }
218};
219#endif
220
diff --git a/toxcore/util.h b/toxcore/util.h
index ae364d52..e40b6968 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -45,11 +45,4 @@ typedef int (*load_state_callback_func)(void *outer, uint8_t *data, uint32_t len
45int load_state(load_state_callback_func load_state_callback, void *outer, 45int load_state(load_state_callback_func load_state_callback, void *outer,
46 uint8_t *data, uint32_t length, uint16_t cookie_inner); 46 uint8_t *data, uint32_t length, uint16_t cookie_inner);
47 47
48#ifdef LOGGING
49extern char logbuffer[512];
50void loginit(uint16_t port);
51void loglog(char *text);
52void logexit();
53#endif
54
55#endif /* __UTIL_H__ */ 48#endif /* __UTIL_H__ */