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 @@ if BUILD_TESTS -TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test -check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test +#TESTS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test +#check_PROGRAMS = messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test +TESTS = toxav_basic_test +check_PROGRAMS = toxav_basic_test AUTOTEST_CFLAGS = \ $(LIBSODIUM_CFLAGS) \ @@ -19,58 +21,58 @@ AUTOTEST_LDADD = \ if BUILD_AV -TESTS += toxav_basic_test -check_PROGRAMS += toxav_basic_test +#TESTS += toxav_basic_test +#check_PROGRAMS += toxav_basic_test AUTOTEST_LDADD += libtoxav.la endif -messenger_autotest_SOURCES = ../auto_tests/messenger_test.c +#messenger_autotest_SOURCES = ../auto_tests/messenger_test.c -messenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS) +#messenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS) -messenger_autotest_LDADD = $(AUTOTEST_LDADD) +#messenger_autotest_LDADD = $(AUTOTEST_LDADD) -crypto_test_SOURCES = ../auto_tests/crypto_test.c +#crypto_test_SOURCES = ../auto_tests/crypto_test.c -crypto_test_CFLAGS = $(AUTOTEST_CFLAGS) +#crypto_test_CFLAGS = $(AUTOTEST_CFLAGS) -crypto_test_LDADD = $(AUTOTEST_LDADD) +#crypto_test_LDADD = $(AUTOTEST_LDADD) -network_test_SOURCES = ../auto_tests/network_test.c +#network_test_SOURCES = ../auto_tests/network_test.c -network_test_CFLAGS = $(AUTOTEST_CFLAGS) +#network_test_CFLAGS = $(AUTOTEST_CFLAGS) -network_test_LDADD = $(AUTOTEST_LDADD) +#network_test_LDADD = $(AUTOTEST_LDADD) -assoc_test_SOURCES = ../auto_tests/assoc_test.c +#assoc_test_SOURCES = ../auto_tests/assoc_test.c -assoc_test_CFLAGS = $(AUTOTEST_CFLAGS) +#assoc_test_CFLAGS = $(AUTOTEST_CFLAGS) -assoc_test_LDADD = $(AUTOTEST_LDADD) +#assoc_test_LDADD = $(AUTOTEST_LDADD) -onion_test_SOURCES = ../auto_tests/onion_test.c +#onion_test_SOURCES = ../auto_tests/onion_test.c -onion_test_CFLAGS = $(AUTOTEST_CFLAGS) +#onion_test_CFLAGS = $(AUTOTEST_CFLAGS) -onion_test_LDADD = $(AUTOTEST_LDADD) +#onion_test_LDADD = $(AUTOTEST_LDADD) -TCP_test_SOURCES = ../auto_tests/TCP_test.c +#TCP_test_SOURCES = ../auto_tests/TCP_test.c -TCP_test_CFLAGS = $(AUTOTEST_CFLAGS) +#TCP_test_CFLAGS = $(AUTOTEST_CFLAGS) -TCP_test_LDADD = $(AUTOTEST_LDADD) +#TCP_test_LDADD = $(AUTOTEST_LDADD) -tox_test_SOURCES = ../auto_tests/tox_test.c +#tox_test_SOURCES = ../auto_tests/tox_test.c -tox_test_CFLAGS = $(AUTOTEST_CFLAGS) +#tox_test_CFLAGS = $(AUTOTEST_CFLAGS) -tox_test_LDADD = $(AUTOTEST_LDADD) +#tox_test_LDADD = $(AUTOTEST_LDADD) if 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 @@ #include #include "../toxcore/tox.h" +#include "../toxcore/logger.h" #include "../toxav/toxav.h" #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) @@ -22,6 +23,7 @@ #endif + typedef enum _CallStatus { none, InCall, @@ -36,6 +38,7 @@ typedef struct _Party { CallStatus status; ToxAv *av; time_t *CallStarted; + int call_index; } Party; typedef struct _Status { @@ -45,42 +48,41 @@ typedef struct _Status { void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) { - if (length == 15 && memcmp("ILIKESMALLTITS", data, 15) == 0) { + if (length == 7 && memcmp("gentoo", data, 7) == 0) { tox_add_friend_norequest(m, public_key); } } /******************************************************************************/ -void callback_recv_invite ( void *_arg ) +void callback_recv_invite ( uint32_t call_index, void *_arg ) { Status *cast = _arg; - + /* Bob always receives invite */ cast->Bob.status = Ringing; + cast->Bob.call_index = call_index; } -void callback_recv_ringing ( void *_arg ) +void callback_recv_ringing ( uint32_t call_index, void *_arg ) { Status *cast = _arg; /* Alice always sends invite */ cast->Alice.status = Ringing; } -void callback_recv_starting ( void *_arg ) +void callback_recv_starting ( uint32_t call_index, void *_arg ) { Status *cast = _arg; /* Alice always sends invite */ printf("Call started on Alice side...\n"); cast->Alice.status = InCall; - toxav_prepare_transmission(cast->Alice.av, 1); + toxav_prepare_transmission(cast->Alice.av, call_index, 1); } -void callback_recv_ending ( void *_arg ) +void callback_recv_ending ( uint32_t call_index, void *_arg ) { Status *cast = _arg; - - if ( cast->Alice.status == Rejected) { printf ( "Call ended for Bob!\n" ); cast->Bob.status = Ended; @@ -90,28 +92,28 @@ void callback_recv_ending ( void *_arg ) } } -void callback_recv_error ( void *_arg ) +void callback_recv_error ( uint32_t call_index, void *_arg ) { ck_assert_msg(0, "AV internal error"); } -void callback_call_started ( void *_arg ) +void callback_call_started ( uint32_t call_index, void *_arg ) { Status *cast = _arg; /* Alice always sends invite */ printf("Call started on Bob side...\n"); cast->Bob.status = InCall; - toxav_prepare_transmission(cast->Bob.av, 1); + toxav_prepare_transmission(cast->Bob.av, call_index, 1); } -void callback_call_canceled ( void *_arg ) +void callback_call_canceled ( uint32_t call_index, void *_arg ) { Status *cast = _arg; printf ( "Call Canceled for Bob!\n" ); cast->Bob.status = Cancel; } -void callback_call_rejected ( void *_arg ) +void callback_call_rejected ( uint32_t call_index, void *_arg ) { Status *cast = _arg; @@ -120,7 +122,7 @@ void callback_call_rejected ( void *_arg ) /* If Bob rejects, call is ended for alice and she sends ending */ cast->Alice.status = Rejected; } -void callback_call_ended ( void *_arg ) +void callback_call_ended ( uint32_t call_index, void *_arg ) { Status *cast = _arg; @@ -128,7 +130,7 @@ void callback_call_ended ( void *_arg ) cast->Bob.status = Ended; } -void callback_requ_timeout ( void *_arg ) +void callback_requ_timeout ( uint32_t call_index, void *_arg ) { ck_assert_msg(0, "No answer!"); } @@ -142,9 +144,9 @@ void callback_requ_timeout ( void *_arg ) tox_do(bootstrap_node); tox_do(Alice); tox_do(Bob); \ switch ( step ) {\ case 0: /* Alice */ printf("Alice is calling...\n");\ - toxav_call(status_control.Alice.av, 0, AliceCallType, 10); step++; break;\ + toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, AliceCallType, 10); step++; break;\ case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob answers...\n");\ - cur_time = time(NULL); toxav_answer(status_control.Bob.av, BobCallType); step++; } break; \ + cur_time = time(NULL); toxav_answer(status_control.Bob.av, status_control.Bob.call_index, BobCallType); step++; } break; \ case 2: /* Rtp transmission */ \ if (status_control.Bob.status == InCall && status_control.Alice.status == InCall) @@ -153,7 +155,7 @@ void callback_requ_timeout ( void *_arg ) case 3: /* Wait for Both to have status ended */\ if (status_control.Alice.status == Ended && status_control.Bob.status == Ended) running = 0; break; } c_sleep(20); } } printf("\n"); -START_TEST(test_AV) +START_TEST(test_AV_flows) { long long unsigned int cur_time = time(NULL); Tox *bootstrap_node = tox_new(0); @@ -166,7 +168,7 @@ START_TEST(test_AV) tox_callback_friend_request(Alice, accept_friend_request, &to_compare); uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; tox_get_address(Alice, address); - int test = tox_add_friend(Bob, address, (uint8_t *)"ILIKESMALLTITS", 15); + int test = tox_add_friend(Bob, address, (uint8_t *)"gentoo", 7); ck_assert_msg(test == 0, "Failed to add friend error code: %i", test); @@ -195,8 +197,8 @@ START_TEST(test_AV) muhcaps.video_height = muhcaps.video_width = 128; Status status_control = { - {none, toxav_new(Alice, &muhcaps), NULL}, - {none, toxav_new(Bob, &muhcaps), NULL}, + {none, toxav_new(Alice, &muhcaps, 1), NULL}, + {none, toxav_new(Bob, &muhcaps, 1), NULL}, }; @@ -235,23 +237,23 @@ START_TEST(test_AV) */ CALL_AND_START_LOOP(TypeAudio, TypeAudio) { /* Both send */ - toxav_send_audio(status_control.Alice.av, sample_payload, 10); - toxav_send_audio(status_control.Bob.av, sample_payload, 10); + toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10); + toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10); /* Both receive */ int16_t storage[10]; int recved; - /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Alice.av, 10, storage); + /* Payload from Bob */ + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ memset(storage, 0, 10); } - /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Bob.av, 10, storage); + /* Payload from Alice */ + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ @@ -259,11 +261,11 @@ START_TEST(test_AV) if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ step++; /* This terminates the loop */ - toxav_kill_transmission(status_control.Alice.av); - toxav_kill_transmission(status_control.Bob.av); + toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); + toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index); /* Call over Alice hangs up */ - toxav_hangup(status_control.Alice.av); + toxav_hangup(status_control.Alice.av, status_control.Alice.call_index); } } TERMINATE_SCOPE() @@ -274,10 +276,10 @@ START_TEST(test_AV) */ CALL_AND_START_LOOP(TypeAudio, TypeVideo) { /* Both send */ - toxav_send_audio(status_control.Alice.av, sample_payload, 10); + toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10); - toxav_send_audio(status_control.Bob.av, sample_payload, 10); - toxav_send_video(status_control.Bob.av, sample_image); + toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10); + toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); /* Both receive */ int16_t storage[10]; @@ -285,7 +287,7 @@ START_TEST(test_AV) int recved; /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Alice.av, 10, storage); + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ @@ -293,7 +295,7 @@ START_TEST(test_AV) } /* Video payload */ - toxav_recv_video(status_control.Alice.av, &video_storage); + toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage); if ( video_storage ) { /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || @@ -305,7 +307,7 @@ START_TEST(test_AV) /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Bob.av, 10, storage); + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ @@ -313,11 +315,11 @@ START_TEST(test_AV) if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ step++; /* This terminates the loop */ - toxav_kill_transmission(status_control.Alice.av); - toxav_kill_transmission(status_control.Bob.av); + toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); + toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index); /* Call over Alice hangs up */ - toxav_hangup(status_control.Alice.av); + toxav_hangup(status_control.Alice.av, status_control.Alice.call_index); } } TERMINATE_SCOPE() @@ -328,11 +330,11 @@ START_TEST(test_AV) */ CALL_AND_START_LOOP(TypeVideo, TypeVideo) { /* Both send */ - toxav_send_audio(status_control.Alice.av, sample_payload, 10); - toxav_send_video(status_control.Alice.av, sample_image); + toxav_send_audio(status_control.Alice.av, status_control.Alice.call_index, sample_payload, 10); + toxav_send_video(status_control.Alice.av, status_control.Alice.call_index, sample_image); - toxav_send_audio(status_control.Bob.av, sample_payload, 10); - toxav_send_video(status_control.Bob.av, sample_image); + toxav_send_audio(status_control.Bob.av, status_control.Bob.call_index, sample_payload, 10); + toxav_send_video(status_control.Bob.av, status_control.Bob.call_index, sample_image); /* Both receive */ int16_t storage[10]; @@ -340,7 +342,7 @@ START_TEST(test_AV) int recved; /* Payload from Bob */ - recved = toxav_recv_audio(status_control.Alice.av, 10, storage); + recved = toxav_recv_audio(status_control.Alice.av, status_control.Alice.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Bob is invalid");*/ @@ -348,7 +350,7 @@ START_TEST(test_AV) } /* Video payload */ - toxav_recv_video(status_control.Alice.av, &video_storage); + toxav_recv_video(status_control.Alice.av, status_control.Alice.call_index, &video_storage); if ( video_storage ) { /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || @@ -360,14 +362,14 @@ START_TEST(test_AV) /* Payload from Alice */ - recved = toxav_recv_audio(status_control.Bob.av, 10, storage); + recved = toxav_recv_audio(status_control.Bob.av, status_control.Bob.call_index, 10, storage); if ( recved ) { /*ck_assert_msg(recved == 10 && memcmp(storage, sample_payload, 10) == 0, "Payload from Alice is invalid");*/ } /* Video payload */ - toxav_recv_video(status_control.Bob.av, &video_storage); + toxav_recv_video(status_control.Bob.av, status_control.Bob.call_index, &video_storage); if ( video_storage ) { /*ck_assert_msg( memcmp(video_storage->planes[VPX_PLANE_Y], sample_payload, 10) == 0 || @@ -378,11 +380,11 @@ START_TEST(test_AV) if (time(NULL) - cur_time > 10) { /* Transmit for 10 seconds */ step++; /* This terminates the loop */ - toxav_kill_transmission(status_control.Alice.av); - toxav_kill_transmission(status_control.Bob.av); + toxav_kill_transmission(status_control.Alice.av, status_control.Alice.call_index); + toxav_kill_transmission(status_control.Bob.av, status_control.Bob.call_index); /* Call over Alice hangs up */ - toxav_hangup(status_control.Alice.av); + toxav_hangup(status_control.Alice.av, status_control.Alice.call_index); } } TERMINATE_SCOPE() @@ -408,7 +410,7 @@ START_TEST(test_AV) switch ( step ) { case 0: /* Alice */ printf("Alice is calling...\n"); - toxav_call(status_control.Alice.av, 0, TypeAudio, 10); + toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10); step++; break; \ @@ -416,7 +418,7 @@ START_TEST(test_AV) case 1: /* Bob */ if (status_control.Bob.status == Ringing) { printf("Bob rejects...\n"); - toxav_reject(status_control.Bob.av, "Who likes D's anyway?"); + toxav_reject(status_control.Bob.av, status_control.Bob.call_index, "Who likes D's anyway?"); step++; } @@ -450,7 +452,7 @@ START_TEST(test_AV) switch ( step ) { case 0: /* Alice */ printf("Alice is calling...\n"); - toxav_call(status_control.Alice.av, 0, TypeAudio, 10); + toxav_call(status_control.Alice.av, &status_control.Alice.call_index, 0, TypeAudio, 10); step++; break; \ @@ -458,7 +460,7 @@ START_TEST(test_AV) case 1: /* Alice again */ if (status_control.Bob.status == Ringing) { printf("Alice cancels...\n"); - toxav_cancel(status_control.Alice.av, 0, "Who likes D's anyway?"); + toxav_cancel(status_control.Alice.av, status_control.Alice.call_index, 0, "Who likes D's anyway?"); step++; } @@ -484,20 +486,29 @@ END_TEST /*************************************************************************************************/ +/*************************************************************************************************/ + +/*************************************************************************************************/ + Suite *tox_suite(void) { Suite *s = suite_create("ToxAV"); - TCase *tc_av = tcase_create("A/V"); - tcase_add_test(tc_av, test_AV); - tcase_set_timeout(tc_av, 100); /* Timeout on 100 too much? */ - suite_add_tcase(s, tc_av); + TCase *tc_av_flows = tcase_create("AV_flows"); + tcase_add_test(tc_av_flows, test_AV_flows); + tcase_set_timeout(tc_av_flows, 100); /* Timeout on 100 too much? */ + suite_add_tcase(s, tc_av_flows); + + TCase *tc_av_three_calls = tcase_create("AV_three_calls"); + tcase_add_test(tc_av_three_calls, test_AV_three_calls); + tcase_set_timeout(tc_av_three_calls, 100); /* Timeout on 100 too much? */ + suite_add_tcase(s, tc_av_three_calls); return s; } int main(int argc, char *argv[]) -{ +{ Suite *tox = tox_suite(); SRunner *test_runner = srunner_create(tox); 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 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../toxcore/tox.h" +#include "../toxcore/logger.h" +#include "../toxav/toxav.h" + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#define c_sleep(x) Sleep(1*x) +#else +#include +#define c_sleep(x) usleep(1000*x) +#endif + + + +typedef enum _CallStatus { + none, + InCall, + Ringing, + Ended, + Rejected, + Cancel + +} CallStatus; + +typedef struct _Party { + CallStatus status; + ToxAv *av; + time_t *CallStarted; + int call_index; +} Party; + +typedef struct _Status { + Party Alice; + Party Bob; +} Status; + +void accept_friend_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 7 && memcmp("gentoo", data, 7) == 0) { + tox_add_friend_norequest(m, public_key); + } +} + + +/******************************************************************************/ +void callback_recv_invite ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Ringing; + cast->call_index = call_index; +} +void callback_recv_ringing ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Ringing; +} +void callback_recv_starting ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = InCall; + toxav_prepare_transmission(cast->av, call_index, 1); +} +void callback_recv_ending ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Ended; +} + +void callback_recv_error ( uint32_t call_index, void *_arg ) +{ + ck_assert_msg(0, "AV internal error"); +} + +void callback_call_started ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = InCall; + toxav_prepare_transmission(cast->av, call_index, 1); +} +void callback_call_canceled ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Cancel; +} +void callback_call_rejected ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Rejected; +} +void callback_call_ended ( uint32_t call_index, void *_arg ) +{ + Party *cast = _arg; + + cast->status = Ended; +} + +void callback_requ_timeout ( uint32_t call_index, void *_arg ) +{ + ck_assert_msg(0, "No answer!"); +} +/*************************************************************************************************/ 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" BUILD_PHONE="no" BUILD_TESTING="yes" +LOGGING="no" +LOGGING_OUTNAM="libtoxcore.log" + NCURSES_FOUND="no" LIBCONFIG_FOUND="no" LIBCHECK_FOUND="no" @@ -80,6 +83,55 @@ AC_ARG_ENABLE([randombytes-stir], ] ) +AC_ARG_ENABLE([logging], + [AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ], + [ + if test "x$enableval" = "xyes"; then + LOGGING="yes" + + AC_DEFINE([LOGGING], [], [If logging enabled]) + AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value]) + AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$LOGGING_OUTNAM"], [Output of logger]) + fi + ] +) + +AC_ARG_WITH(logger-level, + AC_HELP_STRING([--with-logger-level=LEVEL], + [Logger levels: INFO; DEBUG; WARNING; ERROR ]), + [ + if test "x$LOGGING" = "xno"; then + AC_MSG_WARN([Logging disabled!]) + else + if test "x$withval" = "xINFO"; then + AC_DEFINE([LOGGER_LEVEL], [INFO], [LoggerLevel value]) + + elif test "x$withval" = "xDEBUG"; then + AC_DEFINE([LOGGER_LEVEL], [DEBUG], [LoggerLevel value]) + + elif test "x$withval" = "xWARNING"; then + AC_DEFINE([LOGGER_LEVEL], [WARNING], [LoggerLevel value]) + + elif test "x$withval" = "xERROR"; then + AC_DEFINE([LOGGER_LEVEL], [ERROR], [LoggerLevel value]) + else + AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG']) + fi + fi + ] +) + +AC_ARG_WITH(logger-path, + AC_HELP_STRING([--with-logger-path=DIR], + [Path of logger output]), + [ + if test "x$LOGGING" = "xno"; then + AC_MSG_WARN([Logging disabled!]) + else + AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], ["$withval""/""$LOGGING_OUTNAM"], [Output of logger]) + fi + ] +) PKG_PROG_PKG_CONFIG 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 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#define _BSD_SOURCE +#include "../toxcore/logger.h" + +/*#define _BSD_SOURCE*/ #include "msi.h" #include "event.h" @@ -120,10 +122,13 @@ static struct _Callbacks { void* data; } callbacks[11] = {0}; -inline__ void invoke_callback(MSICallbackID id) +inline__ void invoke_callback(uint32_t call_index, MSICallbackID id) { /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ - if ( callbacks[id].function ) callbacks[id].function ( callbacks[id].data ); + if ( callbacks[id].function ) { + LOGGER_DEBUG("Invoking callback function: %d", id); + callbacks[id].function ( call_index, callbacks[id].data ); + } } /*static MSICallback callbacks[10] = {0};*/ @@ -230,7 +235,9 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response ) */ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) { - assert ( msg ); + if ( msg == NULL ) { + LOGGER_ERROR("Could not parse message: no storage!"); + } if ( data[length - 1] ) /* End byte must have value 0 */ return -1; @@ -271,7 +278,7 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) if ON_HEADER ( _it, msg->version, VERSION_FIELD, 7 ) else if ON_HEADER ( _it, msg->request, REQUEST_FIELD, 7 ) else if ON_HEADER ( _it, msg->callid, CALLID_FIELD, 7 ) - } + } break; case 8: { /* Response header */ @@ -290,9 +297,13 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) break; default: + LOGGER_ERROR("Unkown field value"); return -1; } - } else return -1; + } else { + LOGGER_ERROR("Invalid field byte or field size too large"); + return -1; + } /* If it's anything else return failure as the message is invalid */ @@ -304,8 +315,9 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) #define ALLOCATE_HEADER( var, mheader_value, t_size) \ var.header_value = calloc(sizeof *mheader_value, t_size); \ -memcpy(var.header_value, mheader_value, t_size); \ -var.size = t_size; +if (var.header_value == NULL) { LOGGER_WARNING("Header allocation failed!"); } \ +else { memcpy(var.header_value, mheader_value, t_size); \ +var.size = t_size; } /** @@ -316,7 +328,9 @@ var.size = t_size; */ void free_message ( MSIMessage *msg ) { - assert ( msg ); + if ( msg == NULL ) { + LOGGER_ERROR("Tried to free empty message"); + } free ( msg->calltype.header_value ); free ( msg->request.header_value ); @@ -343,7 +357,11 @@ void free_message ( MSIMessage *msg ) MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) { MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); - assert ( _retu ); + + if ( _retu == NULL ) { + LOGGER_WARNING("Allocation failed!"); + return NULL; + } if ( type == TYPE_REQUEST ) { 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 ) */ MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) { - assert ( data ); + if ( data == NULL ) { + LOGGER_WARNING("Tried to parse empty message!"); + return NULL; + } MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); - assert ( _retu ); + + if ( _retu == NULL ) { + LOGGER_WARNING("Allocation failed!"); + return NULL; + } memset ( _retu, 0, sizeof ( MSIMessage ) ); @@ -396,6 +421,42 @@ MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) +/** + * @brief Makes clear message presentation + * + * @param msg Message + * @param dest Dest string + * @return int + */ +int stringify_message(MSIMessage* msg, char* dest) +{ + #define HDR_TO_STR(__dest, __hdr) if (__hdr.header_value) {\ + char nltstr[MSI_MAXMSG_SIZE]; memset(nltstr, '\0', MSI_MAXMSG_SIZE); int i = 0; \ + for ( ; i < __hdr.size; i ++) nltstr[i] = (char)__hdr.header_value[i]; \ + } + + if ( !msg || !dest ) + return -1; + + HDR_TO_STR(dest, msg->version); + HDR_TO_STR(dest, msg->request); + HDR_TO_STR(dest, msg->response); + HDR_TO_STR(dest, msg->reason); + HDR_TO_STR(dest, msg->callid); + HDR_TO_STR(dest, msg->calltype); + HDR_TO_STR(dest, msg->cryptokey); + HDR_TO_STR(dest, msg->nonce); + +// if (msg->version.header_value) { +// U8_TO_NLTCHAR(msg->version.header_value, msg->version.size, nltstr, MSI_MAXMSG_SIZE); +// sprintf(dest, "Version: %s\n", nltstr); +// } + + return 0; +} + + + /** * @brief Speaks for it self. * @@ -413,10 +474,20 @@ uint8_t *append_header_to_string ( uint16_t value_len, uint16_t *length ) { - assert ( dest ); - assert ( header_value ); - assert ( header_field ); - + if ( dest == NULL ) { + LOGGER_ERROR("No destination space!"); + assert(dest); + } + if (header_value == NULL) { + LOGGER_ERROR("Empty header value"); + return NULL; + } + if ( header_field == NULL ) { + LOGGER_ERROR("Empty header field"); + return NULL; + } + + const uint8_t *_hvit = header_value; uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ @@ -477,10 +548,16 @@ if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*) * @param dest Destination. * @return uint16_t It's final size. */ -uint16_t message_to_string ( MSIMessage *msg, uint8_t *dest ) +uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest ) { - assert ( msg ); - assert ( dest ); + if (msg == NULL) { + LOGGER_ERROR("Empty message!"); + return 0; + } + if (dest == NULL ) { + LOGGER_ERROR("Empty destination!"); + return 0; + } uint8_t *_iterated = dest; uint16_t _size = 0; @@ -525,7 +602,10 @@ GENERIC_SETTER_DEFINITION ( nonce ) */ void t_randomstr ( uint8_t *str, size_t size ) { - assert ( str ); + if (str == NULL) { + LOGGER_DEBUG("Empty destination!"); + return; + } static const uint8_t _bytes[] = "0123456789" @@ -607,14 +687,32 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code ) * @retval -1 Error occured. * @retval 0 Success. */ -int send_message ( MSISession *session, MSIMessage *msg, uint32_t to ) +int send_message ( MSISession *session, MSICall* call, MSIMessage *msg, uint32_t to ) { - msi_msg_set_callid ( msg, session->call->id, CALL_ID_LEN ); + msi_msg_set_callid ( msg, call->id, CALL_ID_LEN ); uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; - uint16_t _length = message_to_string ( msg, _msg_string_final ); - - return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; + uint16_t _length = message_to_send ( msg, _msg_string_final ); + + if (!_length) { + LOGGER_WARNING("Parsing message failed; nothing sent!"); + return -1; + } + + /* + LOGGER_SCOPE( + char cast[MSI_MAXMSG_SIZE]; + stringify_message(msg, cast); + LOGGER_DEBUG("[Call: %s] [to: %u] Sending message: len: %d\n%s", call->id, to, _length, cast); + );*/ + + + if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) { + LOGGER_DEBUG("Sent message"); + return 0; + } + + return -1; } @@ -646,7 +744,7 @@ int call_id_bigger( const uint8_t* first, const uint8_t* second) * @param peer_id The peer. * @return void */ -void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id ) +void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id ) { if ( msg->calltype.header_value ) { 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 ) hdrval[msg->calltype.size] = '\0'; if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) { - session->call->type_peer[peer_id] = type_audio; + call->type_peer[peer_id] = type_audio; } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { - session->call->type_peer[peer_id] = type_video; + call->type_peer[peer_id] = type_video; } else {} /* Error */ } else {} /* Error */ } @@ -669,13 +767,17 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8 switch ( status ) { case 0: { /* Went offline */ - if ( session->call ) { + uint32_t j =0; + for ( ; j < session->max_calls; j ++ ) { + + if ( !session->calls[j] ) continue; + int i = 0; - - for ( ; i < session->call->peer_count; i ++ ) - if ( session->call->peers[i] == friend_num ) { - invoke_callback(MSI_OnPeerTimeout); - return; + for ( ; i < session->calls[j]->peer_count; i ++ ) + if ( session->calls[j]->peers[i] == friend_num ) { + invoke_callback(j, MSI_OnPeerTimeout); + LOGGER_DEBUG("Remote: %d timed out!", friend_num); + return; /* TODO: On group calls change behaviour */ } } } @@ -686,6 +788,18 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8 } } +MSICall* find_call ( MSISession* session, uint8_t* call_id ) +{ + if ( call_id == NULL ) return NULL; + + uint32_t i = 0; + for (; i < session->max_calls; i ++ ) + if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) + return session->calls[i]; + + return NULL; +} + /** * @brief Sends error response to peer. * @@ -695,20 +809,22 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8 * @return int * @retval 0 It's always success. */ -int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) +int handle_error ( MSISession *session, MSICall* call, MSICallError errid, uint32_t to ) { + LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); + MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); const uint8_t *_error_code_str = stringify_error_code ( errid ); msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) ); - send_message ( session, _msg_error, to ); + send_message ( session, call, _msg_error, to ); free_message ( _msg_error ); session->last_error_id = errid; session->last_error_str = stringify_error ( errid ); - invoke_callback(MSI_OnError); + invoke_callback(call->call_idx, MSI_OnError); return 0; } @@ -723,16 +839,16 @@ int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) * @retval -1 No error. * @retval 0 Error occured and response sent. */ -int has_call_error ( MSISession *session, MSIMessage *msg ) +int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg ) { if ( !msg->callid.header_value ) { - return handle_error ( session, error_no_callid, msg->friend_id ); + return handle_error ( session, call, error_no_callid, msg->friend_id ); - } else if ( !session->call ) { - return handle_error ( session, error_no_call, msg->friend_id ); + } else if ( !call ) { + return handle_error ( session, call, error_no_call, msg->friend_id ); - } else if ( memcmp ( session->call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { - return handle_error ( session, error_id_mismatch, msg->friend_id ); + } else if ( memcmp ( call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { + return handle_error ( session, call, error_id_mismatch, msg->friend_id ); } @@ -741,7 +857,7 @@ int has_call_error ( MSISession *session, MSIMessage *msg ) /** - * @brief Function called at request timeout. + * @brief Function called at request timeout. If not called in thread it might cause trouble * * @param arg Control session * @return void* @@ -752,16 +868,18 @@ void *handle_timeout ( void *arg ) * timers on these cancels and terminate call on * their timeout */ - MSISession *_session = arg; + MSICall *_call = arg; + + LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); + + invoke_callback(_call->call_idx, MSI_OnRequestTimeout); - invoke_callback(MSI_OnRequestTimeout); - - if ( _session && _session->call ) { + if ( _call && _call->session ) { /* TODO: Cancel all? */ /* uint16_t _it = 0; for ( ; _it < _session->call->peer_count; _it++ ) */ - msi_cancel ( _session, _session->call->peers [0], "Request timedout" ); + msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); } pthread_exit(NULL); @@ -798,14 +916,41 @@ void add_peer( MSICall *call, int peer_id ) */ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) { - assert ( session ); - assert ( peers ); + + if (peers == 0) { + LOGGER_ERROR("No peers!"); + return NULL; + } + + uint32_t _call_idx = 0; + for (; _call_idx < session->max_calls; _call_idx ++) { + if ( !session->calls[_call_idx] ) { + session->calls[_call_idx] = calloc ( sizeof ( MSICall ), 1 ); + break; + } + } + + if ( _call_idx == session->max_calls ) { + LOGGER_WARNING("Reached maximum amount of calls!"); + } + - MSICall *_call = calloc ( sizeof ( MSICall ), 1 ); + MSICall *_call = session->calls[_call_idx]; + _call->call_idx = _call_idx; + + if ( _call == NULL ) { + LOGGER_WARNING("Allocation failed!"); + return NULL; + } + _call->type_peer = calloc ( sizeof ( MSICallType ), peers ); - - assert ( _call ); - assert ( _call->type_peer ); + + if ( _call->type_peer == NULL ) { + LOGGER_WARNING("Allocation failed!"); + return NULL; + } + + _call->session = session; /*_call->_participant_count = _peers;*/ @@ -821,6 +966,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) pthread_mutex_init ( &_call->mutex, NULL ); + LOGGER_DEBUG("Started new call with index: %u", _call_idx); return _call; } @@ -833,51 +979,48 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) * @retval -1 Error occured. * @retval 0 Success. */ -int terminate_call ( MSISession *session ) +int terminate_call ( MSISession *session, MSICall *call ) { - assert ( session ); - - if ( !session->call ) + if ( !call ) { + LOGGER_WARNING("Tried to terminate non-existing call!"); return -1; - + } /* Check event loop and cancel timed events if there are any * NOTE: This has to be done before possibly * locking the mutex the second time */ - event.timer_release ( session->call->request_timer_id ); - event.timer_release ( session->call->ringing_timer_id ); + event.timer_release ( call->request_timer_id ); + event.timer_release ( call->ringing_timer_id ); /* Get a handle */ - pthread_mutex_lock ( &session->call->mutex ); + pthread_mutex_lock ( &call->mutex ); + + session->calls[call->call_idx]= NULL; - MSICall *_call = session->call; - session->call = NULL; - - free ( _call->type_peer ); - free ( _call->key_local ); - free ( _call->key_peer ); - free ( _call->peers); + free ( call->type_peer ); + free ( call->key_local ); + free ( call->key_peer ); + free ( call->peers); /* Release handle */ - pthread_mutex_unlock ( &_call->mutex ); + pthread_mutex_unlock ( &call->mutex ); - pthread_mutex_destroy ( &_call->mutex ); + pthread_mutex_destroy ( &call->mutex ); - free ( _call ); + free ( call ); return 0; } /********** Request handlers **********/ -int handle_recv_invite ( MSISession *session, MSIMessage *msg ) +int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - + LOGGER_DEBUG("Handling 'invite' on call: %s", call? (char*)call->id : "making new"); - if ( session->call ) { - if ( session->call->peers[0] == msg->friend_id ) { + if ( call ) { + if ( call->peers[0] == msg->friend_id ) { /* The glare case. A calls B when at the same time * B calls A. Who has advantage is set bey calculating * 'bigger' Call id and then that call id is being used in @@ -885,8 +1028,8 @@ int handle_recv_invite ( MSISession *session, MSIMessage *msg ) * as in he will wait the reponse from the other. */ - if ( call_id_bigger (session->call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ - terminate_call(session); + if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ + terminate_call(session, call); } else { return 0; /* Wait for ringing from peer */ @@ -894,202 +1037,213 @@ int handle_recv_invite ( MSISession *session, MSIMessage *msg ) } else { - handle_error ( session, error_busy, msg->friend_id ); + handle_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ return 0; } } if ( !msg->callid.header_value ) { - handle_error ( session, error_no_callid, msg->friend_id ); + handle_error ( session, call, error_no_callid, msg->friend_id ); return 0; } - session->call = init_call ( session, 1, 0 ); - memcpy ( session->call->id, msg->callid.header_value, CALL_ID_LEN ); - session->call->state = call_starting; + MSICall* new_call = init_call ( session, 1, 0 ); + + if ( !new_call ) { + handle_error ( session, call, error_busy, msg->friend_id ); + return 0; + } + + memcpy ( new_call->id, msg->callid.header_value, CALL_ID_LEN ); + new_call->state = call_starting; - add_peer( session->call, msg->friend_id); + add_peer( new_call, msg->friend_id); - flush_peer_type ( session, msg, 0 ); + flush_peer_type ( new_call, msg, 0 ); MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); - send_message ( session, _msg_ringing, msg->friend_id ); + send_message ( session, new_call, _msg_ringing, msg->friend_id ); free_message ( _msg_ringing ); - invoke_callback(MSI_OnInvite); + invoke_callback(new_call->call_idx, MSI_OnInvite); return 1; } -int handle_recv_start ( MSISession *session, MSIMessage *msg ) +int handle_recv_start ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - - if ( has_call_error ( session, msg ) == 0 ) - return 0; + LOGGER_DEBUG("Handling 'start' on call: %s", call->id ); + + if ( has_call_error ( session, call, msg ) == 0 ) + return -1; if ( !msg->cryptokey.header_value ) - return handle_error ( session, error_no_crypto_key, msg->friend_id ); + return handle_error ( session, call, error_no_crypto_key, msg->friend_id ); - session->call->state = call_active; + call->state = call_active; - session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); - memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); + call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); + memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); - session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); - memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); + call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); + memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); - flush_peer_type ( session, msg, 0 ); + flush_peer_type ( call, msg, 0 ); - invoke_callback(MSI_OnStart); + invoke_callback(call->call_idx, MSI_OnStart); return 1; } -int handle_recv_reject ( MSISession *session, MSIMessage *msg ) +int handle_recv_reject ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - - if ( has_call_error ( session, msg ) == 0 ) + LOGGER_DEBUG("Handling 'reject' on call: %s", call->id ); + + if ( has_call_error ( session, call, msg ) == 0 ) return 0; MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); - send_message ( session, _msg_ending, msg->friend_id ); + send_message ( session, call, _msg_ending, msg->friend_id ); free_message ( _msg_ending ); - invoke_callback(MSI_OnReject); + invoke_callback(call->call_idx, MSI_OnReject); /* event.timer_release ( session->call->request_timer_id ); session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); */ - terminate_call(session); + terminate_call(session, call); return 1; } -int handle_recv_cancel ( MSISession *session, MSIMessage *msg ) +int handle_recv_cancel ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); + LOGGER_DEBUG("Handling 'cancel' on call: %s", call->id ); - if ( has_call_error ( session, msg ) == 0 ) + if ( has_call_error ( session, call, msg ) == 0 ) return 0; /* Act as end message */ MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); - send_message ( session, _msg_ending, msg->friend_id ); + send_message ( session, call, _msg_ending, msg->friend_id ); free_message ( _msg_ending ); - invoke_callback(MSI_OnCancel); + invoke_callback(call->call_idx, MSI_OnCancel); - terminate_call ( session ); + terminate_call ( session, call ); return 1; } -int handle_recv_end ( MSISession *session, MSIMessage *msg ) +int handle_recv_end ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - - if ( has_call_error ( session, msg ) == 0 ) + LOGGER_DEBUG("Handling 'end' on call: %s", call->id ); + + if ( has_call_error ( session, call, msg ) == 0 ) return 0; MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); - send_message ( session, _msg_ending, msg->friend_id ); + send_message ( session, call, _msg_ending, msg->friend_id ); free_message ( _msg_ending ); - invoke_callback(MSI_OnEnd); + invoke_callback(call->call_idx, MSI_OnEnd); - terminate_call ( session ); + terminate_call ( session, call ); return 1; } /********** Response handlers **********/ -int handle_recv_ringing ( MSISession *session, MSIMessage *msg ) +int handle_recv_ringing ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - - if ( has_call_error ( session, msg ) == 0 ) + LOGGER_DEBUG("Handling 'ringing' on call: %s", call->id ); + + if ( has_call_error ( session, call, msg ) == 0 ) return 0; - session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); + call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms ); - invoke_callback(MSI_OnRinging); + invoke_callback(call->call_idx, MSI_OnRinging); return 1; } -int handle_recv_starting ( MSISession *session, MSIMessage *msg ) +int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - - if ( has_call_error ( session, msg ) == 0 ) + LOGGER_DEBUG("Handling 'starting' on call: %s", call->id ); + + if ( has_call_error ( session, call, msg ) == 0 ) return 0; if ( !msg->cryptokey.header_value ) { - return handle_error ( session, error_no_crypto_key, msg->friend_id ); + return handle_error ( session, call, error_no_crypto_key, msg->friend_id ); } /* Generate local key/nonce to send */ - session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); - new_symmetric_key ( session->call->key_local ); + call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); + new_symmetric_key ( call->key_local ); - session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); - new_nonce ( session->call->nonce_local ); + call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); + new_nonce ( call->nonce_local ); /* Save peer key/nonce */ - session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); - memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); + call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); + memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES ); - session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); - memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); + call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); + memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES ); - session->call->state = call_active; + call->state = call_active; MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); - msi_msg_set_cryptokey ( _msg_start, session->call->key_local, crypto_secretbox_KEYBYTES ); - msi_msg_set_nonce ( _msg_start, session->call->nonce_local, crypto_secretbox_NONCEBYTES ); - send_message ( session, _msg_start, msg->friend_id ); + msi_msg_set_cryptokey ( _msg_start, call->key_local, crypto_secretbox_KEYBYTES ); + msi_msg_set_nonce ( _msg_start, call->nonce_local, crypto_secretbox_NONCEBYTES ); + send_message ( session, call, _msg_start, msg->friend_id ); free_message ( _msg_start ); - flush_peer_type ( session, msg, 0 ); + flush_peer_type ( call, msg, 0 ); - invoke_callback(MSI_OnStarting); + invoke_callback(call->call_idx, MSI_OnStarting); - event.timer_release ( session->call->ringing_timer_id ); + event.timer_release ( call->ringing_timer_id ); return 1; } -int handle_recv_ending ( MSISession *session, MSIMessage *msg ) +int handle_recv_ending ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); + LOGGER_DEBUG("Handling 'ending' on call: %s", call->id ); - if ( has_call_error ( session, msg ) == 0 ) + if ( has_call_error ( session, call, msg ) == 0 ) return 0; /* Stop timer */ - event.timer_release ( session->call->request_timer_id ); + event.timer_release ( call->request_timer_id ); - invoke_callback(MSI_OnEnding); + invoke_callback(call->call_idx, MSI_OnEnding); /* Terminate call */ - terminate_call ( session ); + terminate_call ( session, call ); return 1; } -int handle_recv_error ( MSISession *session, MSIMessage *msg ) +int handle_recv_error ( MSISession *session, MSICall* call, MSIMessage *msg ) { - assert ( session ); - assert ( session->call ); + if ( !call ) { + LOGGER_WARNING("Handling 'error' on non-existing call!"); + return -1; + } + + LOGGER_DEBUG("Handling 'error' on call: %s", call->id ); /* Handle error accordingly */ if ( msg->reason.header_value ) { session->last_error_id = atoi ( ( const char * ) msg->reason.header_value ); session->last_error_str = stringify_error ( session->last_error_id ); + LOGGER_DEBUG("Error reason: %s", session->last_error_str); } - invoke_callback(MSI_OnEnding); + invoke_callback(call->call_idx, MSI_OnEnding); - terminate_call ( session ); + terminate_call ( session, call ); return 1; } @@ -1128,26 +1282,40 @@ int handle_recv_error ( MSISession *session, MSIMessage *msg ) */ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object ) { + LOGGER_DEBUG("Got msi message"); /* Unused */ (void)messenger; MSISession *_session = object; MSIMessage *_msg; - if ( !length ) return; + if ( !length ) { + LOGGER_WARNING("Lenght param negative"); + return; + } _msg = parse_message ( data, length ); - if ( !_msg ) return; + if ( !_msg ) { + LOGGER_WARNING("Error parsing message"); + return; + } else { + LOGGER_DEBUG("Successfully parsed message"); + } _msg->friend_id = source; - - + + /* Find what call */ + MSICall* _call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL; + /* Now handle message */ - + if ( _msg->request.header_value ) { /* Handle request */ - if ( _msg->response.size > 32 ) goto free_end; + if ( _msg->response.size > 32 ) { + LOGGER_WARNING("Header size too big"); + goto free_end; + } uint8_t _request_value[32]; @@ -1155,26 +1323,30 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16 _request_value[_msg->request.size] = '\0'; if ( same ( _request_value, stringify_request ( invite ) ) ) { - handle_recv_invite ( _session, _msg ); + handle_recv_invite ( _session, _call, _msg ); } else if ( same ( _request_value, stringify_request ( start ) ) ) { - handle_recv_start ( _session, _msg ); + handle_recv_start ( _session, _call, _msg ); } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { - handle_recv_cancel ( _session, _msg ); + handle_recv_cancel ( _session, _call, _msg ); } else if ( same ( _request_value, stringify_request ( reject ) ) ) { - handle_recv_reject ( _session, _msg ); + handle_recv_reject ( _session, _call, _msg ); } else if ( same ( _request_value, stringify_request ( end ) ) ) { - handle_recv_end ( _session, _msg ); + handle_recv_end ( _session, _call, _msg ); + } else { + LOGGER_WARNING("Uknown request"); + goto free_end; } - else goto free_end; - } else if ( _msg->response.header_value ) { /* Handle response */ - if ( _msg->response.size > 32 ) goto free_end; + if ( _msg->response.size > 32 ) { + LOGGER_WARNING("Header size too big"); + goto free_end; + } uint8_t _response_value[32]; @@ -1182,23 +1354,28 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16 _response_value[_msg->response.size] = '\0'; if ( same ( _response_value, stringify_response ( ringing ) ) ) { - handle_recv_ringing ( _session, _msg ); + handle_recv_ringing ( _session, _call, _msg ); } else if ( same ( _response_value, stringify_response ( starting ) ) ) { - handle_recv_starting ( _session, _msg ); + handle_recv_starting ( _session, _call, _msg ); } else if ( same ( _response_value, stringify_response ( ending ) ) ) { - handle_recv_ending ( _session, _msg ); + handle_recv_ending ( _session, _call, _msg ); } else if ( same ( _response_value, stringify_response ( error ) ) ) { - handle_recv_error ( _session, _msg ); + handle_recv_error ( _session, _call, _msg ); - } else goto free_end; + } else { + LOGGER_WARNING("Uknown response"); + goto free_end; + } /* Got response so cancel timer */ - if ( _session->call ) - event.timer_release ( _session->call->request_timer_id ); + if ( _call ) + event.timer_release ( _call->request_timer_id ); + } else { + LOGGER_WARNING("Invalid message: no resp nor requ headers"); } free_end:free_message ( _msg ); @@ -1248,21 +1425,31 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd * @brief Start the control session. * * @param messenger Tox* object. - * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' + * @param max_calls Amount of calls possible * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession *msi_init_session ( Messenger* messenger ) +MSISession *msi_init_session ( Messenger* messenger, uint32_t max_calls ) { - assert ( messenger ); + if (messenger == NULL) { + LOGGER_ERROR("Could not init session on empty messenger!"); + return NULL; + } + if ( !max_calls) return NULL; + MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); - assert ( _retu ); + + if (_retu == NULL) { + LOGGER_ERROR("Allocation failed!"); + return NULL; + } _retu->messenger_handle = messenger; _retu->agent_handler = NULL; - _retu->call = NULL; + _retu->calls = calloc( sizeof (MSICall*), max_calls ); + _retu->max_calls = max_calls; _retu->frequ = 10000; /* default value? */ _retu->call_timeout = 30000; /* default value? */ @@ -1272,7 +1459,8 @@ MSISession *msi_init_session ( Messenger* messenger ) /* This is called when remote terminates session */ m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); - + + LOGGER_DEBUG("New msi session: %p max calls: %u", _retu, max_calls); return _retu; } @@ -1285,16 +1473,20 @@ MSISession *msi_init_session ( Messenger* messenger ) */ int msi_terminate_session ( MSISession *session ) { - assert ( session ); + if (session == NULL) { + LOGGER_ERROR("Tried to terminate non-existing session"); + return -1; + } int _status = 0; - /* If have call, cancel it */ - if ( session->call ) { + /* If have calls, cancel them */ + uint32_t idx = 0; + for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) { /* Cancel all? */ uint16_t _it = 0; - for ( ; _it < session->call->peer_count; _it++ ) - msi_cancel ( session, session->call->peers [_it], "MSI session terminated!" ); + for ( ; _it < session->calls[idx]->peer_count; _it++ ) + msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); } m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); @@ -1313,35 +1505,39 @@ int msi_terminate_session ( MSISession *session ) * @param friend_id The friend. * @return int */ -int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) +int msi_invite ( MSISession* session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) { - assert ( session ); - + LOGGER_DEBUG("Inviting friend: %u", friend_id); + MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); + + MSICall* _call = init_call ( session, 1, rngsec ); /* Just one for now */ + if ( !_call ) return -1; /* Cannot handle more calls */ + + *call_index = _call->call_idx; + + t_randomstr ( _call->id, CALL_ID_LEN ); - session->call = init_call ( session, 1, rngsec ); /* Just one for now */ - t_randomstr ( session->call->id, CALL_ID_LEN ); + add_peer(_call, friend_id ); - add_peer(session->call, friend_id ); - - session->call->type_local = call_type; + _call->type_local = call_type; + /* Do whatever with message */ - if ( call_type == type_audio ) { - msi_msg_set_calltype - ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); + msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); } else { - msi_msg_set_calltype - ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) ); + msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) ); } - send_message ( session, _msg_invite, friend_id ); + send_message ( session, _call, _msg_invite, friend_id ); free_message ( _msg_invite ); - session->call->state = call_inviting; - - session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + _call->state = call_inviting; + _call->request_timer_id = event.timer_alloc ( handle_timeout, _call, m_deftout ); + + LOGGER_DEBUG("Invite sent"); + return 0; } @@ -1350,29 +1546,37 @@ int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, ui * @brief Hangup active call. * * @param session Control session. + * @param call_id To which call is this action handled. * @return int * @retval -1 Error occured. * @retval 0 Success. */ -int msi_hangup ( MSISession *session ) +int msi_hangup ( MSISession* session, uint32_t call_index ) { - assert ( session ); - - if ( !session->call || session->call->state != call_active ) + LOGGER_DEBUG("Hanging up call: %u", call_index); + + if ( call_index >= session->max_calls || !session->calls[call_index] ) { + LOGGER_ERROR("Invalid call index!"); return -1; + } + + if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { + LOGGER_ERROR("No call with such index or call is not active!"); + return -1; + } MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); /* hangup for each peer */ int _it = 0; - for ( ; _it < session->call->peer_count; _it ++ ) - send_message ( session, _msg_end, session->call->peers[_it] ); + for ( ; _it < session->calls[call_index]->peer_count; _it ++ ) + send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] ); free_message ( _msg_end ); - session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); return 0; } @@ -1382,15 +1586,22 @@ int msi_hangup ( MSISession *session ) * @brief Answer active call request. * * @param session Control session. + * @param call_id To which call is this action handled. * @param call_type Answer with Audio or Video(both). * @return int */ -int msi_answer ( MSISession *session, MSICallType call_type ) +int msi_answer ( MSISession* session, uint32_t call_index, MSICallType call_type ) { - assert ( session ); - + LOGGER_DEBUG("Answering call: %u", call_index); + + if ( call_index >= session->max_calls || !session->calls[call_index] ){ + LOGGER_ERROR("Invalid call index!"); + return -1; + } + MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); - session->call->type_local = call_type; + + session->calls[call_index]->type_local = call_type; if ( call_type == type_audio ) { msi_msg_set_calltype @@ -1402,19 +1613,19 @@ int msi_answer ( MSISession *session, MSICallType call_type ) /* Now set the local encryption key and pass it with STARTING message */ - session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); - new_symmetric_key ( session->call->key_local ); + session->calls[call_index]->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES ); + new_symmetric_key ( session->calls[call_index]->key_local ); - session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); - new_nonce ( session->call->nonce_local ); + session->calls[call_index]->nonce_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES ); + new_nonce ( session->calls[call_index]->nonce_local ); - msi_msg_set_cryptokey ( _msg_starting, session->call->key_local, crypto_secretbox_KEYBYTES ); - msi_msg_set_nonce ( _msg_starting, session->call->nonce_local, crypto_secretbox_NONCEBYTES ); + msi_msg_set_cryptokey ( _msg_starting, session->calls[call_index]->key_local, crypto_secretbox_KEYBYTES ); + msi_msg_set_nonce ( _msg_starting, session->calls[call_index]->nonce_local, crypto_secretbox_NONCEBYTES ); - send_message ( session, _msg_starting, session->call->peers[session->call->peer_count - 1] ); + send_message ( session, session->calls[call_index], _msg_starting, session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); free_message ( _msg_starting ); - session->call->state = call_active; + session->calls[call_index]->state = call_active; return 0; } @@ -1424,21 +1635,27 @@ int msi_answer ( MSISession *session, MSICallType call_type ) * @brief Cancel request. * * @param session Control session. + * @param call_id To which call is this action handled. * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) +int msi_cancel ( MSISession *session, uint32_t call_index, uint32_t peer, const char *reason ) { - assert ( session ); - + LOGGER_DEBUG("Canceling call: %u; reason:", call_index, reason? reason : "Unknown"); + + if ( call_index >= session->max_calls || !session->calls[call_index] ){ + LOGGER_ERROR("Invalid call index!"); + return -1; + } + MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason)); - send_message ( session, _msg_cancel, peer ); + send_message ( session, session->calls[call_index], _msg_cancel, peer ); free_message ( _msg_cancel ); - session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); return 0; } @@ -1448,20 +1665,26 @@ int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) * @brief Reject request. * * @param session Control session. + * @param call_id To which call is this action handled. * @return int */ -int msi_reject ( MSISession *session, const uint8_t *reason ) +int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason ) { - assert ( session ); - + LOGGER_DEBUG("Rejecting call: %u; reason:", call_index, reason? (char*)reason : "Unknown"); + + if ( call_index >= session->max_calls || !session->calls[call_index] ){ + LOGGER_ERROR("Invalid call index!"); + return -1; + } + MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); - send_message ( session, _msg_reject, session->call->peers[session->call->peer_count - 1] ); + send_message ( session, session->calls[call_index], _msg_reject, session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); free_message ( _msg_reject ); - session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout ); return 0; } @@ -1471,18 +1694,19 @@ int msi_reject ( MSISession *session, const uint8_t *reason ) * @brief Terminate the current call. * * @param session Control session. + * @param call_id To which call is this action handled. * @return int */ -int msi_stopcall ( MSISession *session ) +int msi_stopcall ( MSISession *session, uint32_t call_index ) { - assert ( session ); - - if ( !session->call ) + LOGGER_DEBUG("Stopping call index: %u", call_index); + + if ( call_index >= session->max_calls || !session->calls[call_index] ) return -1; /* just terminate it */ - terminate_call ( session ); + terminate_call ( session, session->calls[call_index] ); return 0; } \ 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 @@ #define CALL_ID_LEN 12 -typedef void ( *MSICallback ) ( void *arg ); +typedef void ( *MSICallback ) ( uint32_t, void *arg ); /** @@ -62,32 +62,34 @@ typedef enum { * @brief The call struct. * */ -typedef struct _MSICall { /* Call info structure */ - MSICallState state; +typedef struct _MSICall { /* Call info structure */ + struct _MSISession* session; /* Session pointer */ + + MSICallState state; - MSICallType type_local; /* Type of payload user is ending */ - MSICallType *type_peer; /* Type of payload others are sending */ + MSICallType type_local; /* Type of payload user is ending */ + MSICallType *type_peer; /* Type of payload others are sending */ - uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ + uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ - uint8_t *key_local; /* The key for encryption */ - uint8_t *key_peer; /* The key for decryption */ + uint8_t *key_local; /* The key for encryption */ + uint8_t *key_peer; /* The key for decryption */ - uint8_t *nonce_local; /* Local nonce */ - uint8_t *nonce_peer; /* Peer nonce */ + uint8_t *nonce_local; /* Local nonce */ + uint8_t *nonce_peer; /* Peer nonce */ - int ringing_tout_ms; /* Ringing timeout in ms */ + int ringing_tout_ms; /* Ringing timeout in ms */ - int request_timer_id; /* Timer id for outgoing request/action */ - int ringing_timer_id; /* Timer id for ringing timeout */ - - pthread_mutex_t mutex; /* It's to be assumed that call will have - * seperate thread so add mutex - */ - uint32_t *peers; - uint16_t peer_count; + int request_timer_id; /* Timer id for outgoing request/action */ + int ringing_timer_id; /* Timer id for ringing timeout */ + pthread_mutex_t mutex; /* It's to be assumed that call will have + * seperate thread so add mutex + */ + uint32_t *peers; + uint16_t peer_count; + uint32_t call_idx; /* Index of this call in MSISession */ } MSICall; @@ -97,8 +99,9 @@ typedef struct _MSICall { /* Call info structure */ */ typedef struct _MSISession { - /* Call handler */ - struct _MSICall *call; + /* Call handlers */ + struct _MSICall **calls; + uint32_t max_calls; int last_error_id; /* Determine the last error */ const uint8_t *last_error_str; @@ -151,10 +154,11 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat * @brief Start the control session. * * @param messenger Tox* object. + * @param max_calls Amount of calls possible * @return MSISession* The created session. * @retval NULL Error occured. */ -MSISession *msi_init_session ( Messenger *messenger ); +MSISession *msi_init_session ( Messenger *messenger, uint32_t max_calls ); /** @@ -170,62 +174,68 @@ int msi_terminate_session ( MSISession *session ); * @brief Send invite request to friend_id. * * @param session Control session. + * @param call_index Set to new call index. * @param call_type Type of the call. Audio or Video(both audio and video) * @param rngsec Ringing timeout. * @param friend_id The friend. * @return int */ -int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); +int msi_invite ( MSISession *session, uint32_t* call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); /** * @brief Hangup active call. * * @param session Control session. + * @param call_index To which call is this action handled. * @return int * @retval -1 Error occured. * @retval 0 Success. */ -int msi_hangup ( MSISession *session ); +int msi_hangup ( MSISession *session, uint32_t call_index ); /** * @brief Answer active call request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param call_type Answer with Audio or Video(both). * @return int */ -int msi_answer ( MSISession *session, MSICallType call_type ); +int msi_answer ( MSISession *session, uint32_t call_index, MSICallType call_type ); /** * @brief Cancel request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param peer To which peer. * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); +int msi_cancel ( MSISession* session, uint32_t call_index, uint32_t peer, const char* reason ); /** * @brief Reject request. * * @param session Control session. + * @param call_index To which call is this action handled. * @param reason Set optional reason header. Pass NULL if none. * @return int */ -int msi_reject ( MSISession *session, const uint8_t *reason ); +int msi_reject ( MSISession *session, uint32_t call_index, const uint8_t *reason ); /** * @brief Terminate the current call. * * @param session Control session. + * @param call_index To which call is this action handled. * @return int */ -int msi_stopcall ( MSISession *session ); +int msi_stopcall ( MSISession *session, uint32_t call_index ); #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 @@ #include "media.h" #include "msi.h" +#include "../toxcore/logger.h" + #include #include #include @@ -43,6 +45,9 @@ static const uint8_t audio_index = 0, video_index = 1; +typedef struct _CallRTPSessions { + RTPSession *crtps[2]; /* Audio is first and video is second */ +} CallRTPSessions; typedef enum { ts_closing, @@ -56,13 +61,27 @@ struct _ToxAv { MSISession *msi_session; /** Main msi session */ - RTPSession *rtp_sessions[2]; /* Audio is first and video is second */ + CallRTPSessions* rtp_sessions; struct jitter_buffer *j_buf; CodecState *cs; + uint32_t max_calls; }; +const ToxAvCodecSettings av_DefaultSettings = { + 1000000, + 800, + 600, + + 64000, + 20, + 48000, + 1, + 20 +}; + + /** * @brief Start new A/V session. There can only be one session at the time. If you register more * it will result in undefined behaviour. @@ -74,7 +93,7 @@ struct _ToxAv { * @return ToxAv* * @retval NULL On error. */ -ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) +ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls) { ToxAv *av = calloc ( sizeof(ToxAv), 1); @@ -83,12 +102,12 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) av->messenger = (Messenger *)messenger; - av->msi_session = msi_init_session(av->messenger); + av->msi_session = msi_init_session(av->messenger, max_calls); av->msi_session->agent_handler = av; - av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; - - /* NOTE: This should be user defined or? */ + av->rtp_sessions = calloc(sizeof(RTPSession), max_calls); + av->max_calls = max_calls; + av->j_buf = create_queue(codec_settings->jbuf_capacity); av->cs = codec_init_session(codec_settings->audio_bitrate, @@ -98,7 +117,7 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) codec_settings->video_width, codec_settings->video_height, codec_settings->video_bitrate); - + return av; } @@ -111,14 +130,19 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) void toxav_kill ( ToxAv *av ) { msi_terminate_session(av->msi_session); - - if ( av->rtp_sessions[audio_index] ) { - rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle); - } - - if ( av->rtp_sessions[video_index] ) { - rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle); + + int i = 0; + for (; i < av->max_calls; i ++) { + if ( av->rtp_sessions[i].crtps[audio_index] ) { + rtp_terminate_session(av->rtp_sessions[i].crtps[audio_index], av->msi_session->messenger_handle); + } + + if ( av->rtp_sessions[i].crtps[video_index] ) { + rtp_terminate_session(av->rtp_sessions[i].crtps[video_index], av->msi_session->messenger_handle); + } } + + free(av->rtp_sessions); codec_terminate_session(av->cs); @@ -148,13 +172,9 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds ) +int toxav_call (ToxAv* av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds ) { - if ( av->msi_session->call ) { - return ErrorAlreadyInCall; - } - - return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user); + return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user); } /** @@ -165,17 +185,17 @@ int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_second * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_hangup ( ToxAv *av ) +int toxav_hangup ( ToxAv* av, uint32_t call_index ) { - if ( !av->msi_session->call ) { + if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - if ( av->msi_session->call->state != call_active ) { + if ( av->msi_session->calls[call_index]->state != call_active ) { return ErrorInvalidState; } - return msi_hangup(av->msi_session); + return msi_hangup(av->msi_session, call_index); } /** @@ -187,17 +207,17 @@ int toxav_hangup ( ToxAv *av ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) +int toxav_answer ( ToxAv* av, uint32_t call_index, ToxAvCallType call_type ) { - if ( !av->msi_session->call ) { + if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - if ( av->msi_session->call->state != call_starting ) { + if ( av->msi_session->calls[call_index]->state != call_starting ) { return ErrorInvalidState; } - return msi_answer(av->msi_session, call_type); + return msi_answer(av->msi_session, call_index, call_type); } /** @@ -209,17 +229,17 @@ int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_reject ( ToxAv *av, const char *reason ) +int toxav_reject ( ToxAv* av, uint32_t call_index, const char* reason ) { - if ( !av->msi_session->call ) { + if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - if ( av->msi_session->call->state != call_starting ) { + if ( av->msi_session->calls[call_index]->state != call_starting ) { return ErrorInvalidState; } - return msi_reject(av->msi_session, (const uint8_t *) reason); + return msi_reject(av->msi_session, call_index, (const uint8_t *) reason); } /** @@ -232,13 +252,13 @@ int toxav_reject ( ToxAv *av, const char *reason ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) +int toxav_cancel ( ToxAv* av, uint32_t call_index, int peer_id, const char* reason ) { - if ( !av->msi_session->call ) { + if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - return msi_cancel(av->msi_session, peer_id, reason); + return msi_cancel(av->msi_session, call_index, peer_id, reason); } /** @@ -249,13 +269,13 @@ int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_stop_call ( ToxAv *av ) +int toxav_stop_call ( ToxAv* av, uint32_t call_index ) { - if ( !av->msi_session->call ) { + if ( !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - return msi_stopcall(av->msi_session); + return msi_stopcall(av->msi_session, call_index); } /** @@ -266,43 +286,43 @@ int toxav_stop_call ( ToxAv *av ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_prepare_transmission ( ToxAv* av, int support_video ) +int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_video ) { - assert(av->msi_session); - - if ( !av->msi_session || !av->msi_session->call ) { + if ( !av->msi_session || !av->msi_session->calls[call_index] ) { return ErrorNoCall; } - av->rtp_sessions[audio_index] = rtp_init_session( - type_audio, - av->messenger, - av->msi_session->call->peers[0], - av->msi_session->call->key_peer, - av->msi_session->call->key_local, - av->msi_session->call->nonce_peer, - av->msi_session->call->nonce_local - ); + av->rtp_sessions[call_index].crtps[audio_index] = + rtp_init_session( + type_audio, + av->messenger, + av->msi_session->calls[call_index]->peers[0], + av->msi_session->calls[call_index]->key_peer, + av->msi_session->calls[call_index]->key_local, + av->msi_session->calls[call_index]->nonce_peer, + av->msi_session->calls[call_index]->nonce_local + ); - if ( !av->rtp_sessions[audio_index] ) { + if ( !av->rtp_sessions[call_index].crtps[audio_index] ) { fprintf(stderr, "Error while starting audio RTP session!\n"); return ErrorStartingAudioRtp; } if ( support_video ) { - av->rtp_sessions[video_index] = rtp_init_session ( - type_video, - av->messenger, - av->msi_session->call->peers[0], - av->msi_session->call->key_peer, - av->msi_session->call->key_local, - av->msi_session->call->nonce_peer, - av->msi_session->call->nonce_local - ); + av->rtp_sessions[call_index].crtps[video_index] = + rtp_init_session ( + type_video, + av->messenger, + av->msi_session->calls[call_index]->peers[0], + av->msi_session->calls[call_index]->key_peer, + av->msi_session->calls[call_index]->key_local, + av->msi_session->calls[call_index]->nonce_peer, + av->msi_session->calls[call_index]->nonce_local + ); - if ( !av->rtp_sessions[video_index] ) { + if ( !av->rtp_sessions[call_index].crtps[video_index] ) { fprintf(stderr, "Error while starting video RTP session!\n"); return ErrorStartingVideoRtp; } @@ -318,20 +338,20 @@ int toxav_prepare_transmission ( ToxAv* av, int support_video ) * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_kill_transmission ( ToxAv *av ) +int toxav_kill_transmission ( ToxAv *av, uint32_t call_index ) { - if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) { + if ( av->rtp_sessions[call_index].crtps[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[audio_index], av->messenger) ) { fprintf(stderr, "Error while terminating audio RTP session!\n"); return ErrorTerminatingAudioRtp; } - if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) { + if ( av->rtp_sessions[call_index].crtps[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[video_index], av->messenger) ) { fprintf(stderr, "Error while terminating video RTP session!\n"); return ErrorTerminatingVideoRtp; } - av->rtp_sessions[audio_index] = NULL; - av->rtp_sessions[video_index] = NULL; + av->rtp_sessions[call_index].crtps[audio_index] = NULL; + av->rtp_sessions[call_index].crtps[video_index] = NULL; return ErrorNone; @@ -349,10 +369,10 @@ int toxav_kill_transmission ( ToxAv *av ) * @retval 0 Success. * @retval -1 Failure. */ -inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length ) +inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length ) { - if ( av->rtp_sessions[type - TypeAudio] ) - return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); + if ( av->rtp_sessions[call_index].crtps[type - TypeAudio] ) + return rtp_send_msg ( av->rtp_sessions[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); else return -1; } @@ -366,18 +386,18 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8 * @retval ToxAvError On Error. * @retval >=0 Size of received payload. */ -inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest ) +inline__ int toxav_recv_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, uint8_t *dest ) { if ( !dest ) return ErrorInternal; - if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession; + if ( !av->rtp_sessions[call_index].crtps[type - TypeAudio] ) return ErrorNoRtpSession; RTPMessage *message; if ( type == TypeAudio ) { do { - message = rtp_recv_msg(av->rtp_sessions[audio_index]); + message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[audio_index]); if (message) { /* push the packet into the queue */ @@ -390,7 +410,7 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de if ( success == 2) return ErrorAudioPacketLost; } else { - message = rtp_recv_msg(av->rtp_sessions[video_index]); + message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[video_index]); } if ( message ) { @@ -415,7 +435,7 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de * @retval 0 Success. * @retval ToxAvError On Error. */ -inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) +inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **output) { if ( !output ) return ErrorInternal; @@ -424,7 +444,7 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) int error; do { - recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); + recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet); if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) 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) * @retval 0 Success. * @retval ToxAvError On error. */ -inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) +inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, vpx_image_t *input) { if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { fprintf(stderr, "Could not encode video frame\n"); @@ -465,7 +485,7 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { - if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) + if (toxav_send_rtp_payload(av, call_index, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) ++sent; } } @@ -488,13 +508,13 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) * @retval >=0 Size of received data in frames/samples. * @retval ToxAvError On error. */ -inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest ) +inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, int16_t *dest ) { if ( !dest ) return ErrorInternal; uint8_t packet [RTP_PAYLOAD_SIZE]; - int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); + int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet); if ( recved_size == ErrorAudioPacketLost ) { 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 ) * @retval 0 Success. * @retval ToxAvError On error. */ -inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) +inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const int16_t *frame, int frame_size) { uint8_t temp_data[RTP_PAYLOAD_SIZE]; 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) if (ret <= 0) return ErrorInternal; - return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); + return toxav_send_rtp_payload(av, call_index, TypeAudio, temp_data, ret); } /** @@ -536,14 +556,14 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) * @retval ToxAvCallType On success. * @retval ToxAvError On error. */ -int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) +int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer ) { assert(av->msi_session); - if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) + if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer ) return ErrorInternal; - return av->msi_session->call->type_peer[peer]; + return av->msi_session->calls[call_index]->type_peer[peer]; } /** @@ -554,14 +574,14 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) * @return int * @retval ToxAvError No peer id */ -int toxav_get_peer_id ( ToxAv* av, int peer ) +int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ) { assert(av->msi_session); - if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) + if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer ) return ErrorInternal; - return av->msi_session->call->peers[peer]; + return av->msi_session->calls[call_index]->peers[peer]; } /** 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 @@ /* vpx_image_t */ #include -typedef void ( *ToxAVCallback ) ( void *arg ); +typedef void ( *ToxAVCallback ) ( uint32_t, void *arg ); typedef struct _ToxAv ToxAv; #ifndef __TOX_DEFINED__ @@ -119,17 +119,7 @@ typedef struct _ToxAvCodecSettings { uint32_t jbuf_capacity; /* Size of jitter buffer */ } ToxAvCodecSettings; -static const ToxAvCodecSettings av_DefaultSettings = { - 1000000, - 800, - 600, - - 64000, - 20, - 48000, - 1, - 20 -}; +extern const ToxAvCodecSettings av_DefaultSettings; /** * @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 = { * @return ToxAv* * @retval NULL On error. */ -ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings); +ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls); /** * @brief Remove A/V session. @@ -172,7 +162,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds); +int toxav_call(ToxAv *av, uint32_t* call_index, int user, ToxAvCallType call_type, int ringing_seconds); /** * @brief Hangup active call. @@ -182,7 +172,7 @@ int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_hangup(ToxAv *av); +int toxav_hangup(ToxAv *av, uint32_t call_index); /** * @brief Answer incomming call. @@ -193,7 +183,7 @@ int toxav_hangup(ToxAv *av); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_answer(ToxAv *av, ToxAvCallType call_type ); +int toxav_answer(ToxAv *av, uint32_t call_index, ToxAvCallType call_type ); /** * @brief Reject incomming call. @@ -204,7 +194,7 @@ int toxav_answer(ToxAv *av, ToxAvCallType call_type ); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_reject(ToxAv *av, const char *reason); +int toxav_reject(ToxAv *av, uint32_t call_index, const char *reason); /** * @brief Cancel outgoing request. @@ -216,7 +206,7 @@ int toxav_reject(ToxAv *av, const char *reason); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_cancel(ToxAv* av, int peer_id, const char* reason); +int toxav_cancel(ToxAv* av, uint32_t call_index, int peer_id, const char* reason); /** * @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); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_stop_call(ToxAv *av); +int toxav_stop_call(ToxAv *av, uint32_t call_index); /** * @brief Must be call before any RTP transmission occurs. @@ -237,7 +227,7 @@ int toxav_stop_call(ToxAv *av); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_prepare_transmission(ToxAv *av, int support_video); +int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, int support_video); /** * @brief Call this at the end of the transmission. @@ -247,7 +237,7 @@ int toxav_prepare_transmission(ToxAv *av, int support_video); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_kill_transmission(ToxAv *av); +int toxav_kill_transmission(ToxAv *av, uint32_t call_index); /** * @brief Receive decoded video packet. @@ -258,7 +248,7 @@ int toxav_kill_transmission(ToxAv *av); * @retval 0 Success. * @retval ToxAvError On Error. */ -int toxav_recv_video ( ToxAv *av, vpx_image_t **output); +int toxav_recv_video ( ToxAv* av, uint32_t call_index, vpx_image_t** output); /** * @brief Receive decoded audio frame. @@ -272,7 +262,7 @@ int toxav_recv_video ( ToxAv *av, vpx_image_t **output); * @retval >=0 Size of received data in frames/samples. * @retval ToxAvError On error. */ -int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); +int toxav_recv_audio( ToxAv* av, uint32_t call_index, int frame_size, int16_t* dest ); /** * @brief Encode and send video packet. @@ -283,7 +273,7 @@ int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_send_video ( ToxAv *av, vpx_image_t *input); +int toxav_send_video ( ToxAv* av, uint32_t call_index, vpx_image_t* input); /** * @brief Encode and send audio frame. @@ -296,7 +286,7 @@ int toxav_send_video ( ToxAv *av, vpx_image_t *input); * @retval 0 Success. * @retval ToxAvError On error. */ -int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size); +int toxav_send_audio ( ToxAv* av, uint32_t call_index, const int16_t* frame, int frame_size); /** * @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); * @retval ToxAvCallType On success. * @retval ToxAvError On error. */ -int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); +int toxav_get_peer_transmission_type ( ToxAv *av, uint32_t call_index, int peer ); /** * @brief Get id of peer participating in conversation @@ -317,7 +307,7 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); * @return int * @retval ToxAvError No peer id */ -int toxav_get_peer_id ( ToxAv* av, int peer ); +int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer ); /** * @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 @@ #include "config.h" #endif +#include "logger.h" + #include "DHT.h" #ifdef ENABLE_ASSOC_DHT @@ -198,18 +200,12 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t /* Refresh the client timestamp. */ if (ip_port.ip.family == AF_INET) { -#ifdef LOGGING - - if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { - size_t x; - x = sprintf(logbuffer, "coipil[%u]: switching ipv4 from %s:%u ", i, - ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port)); - sprintf(logbuffer + x, "to %s:%u\n", - ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); - loglog(logbuffer); - } - -#endif + LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { + LOGGER_INFO("coipil[%u]: switching ipv4 from %s:%u to %s:%u", i, + ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port), + ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); + } + ); if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) return 1; @@ -217,19 +213,13 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t list[i].assoc4.ip_port = ip_port; list[i].assoc4.timestamp = temp_time; } else if (ip_port.ip.family == AF_INET6) { - -#ifdef LOGGING - - if (!ipport_equal(&list[i].assoc6.ip_port, &ip_port)) { - size_t x; - x = sprintf(logbuffer, "coipil[%u]: switching ipv6 from %s:%u ", i, - ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port)); - sprintf(logbuffer + x, "to %s:%u\n", - ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); - loglog(logbuffer); - } - -#endif + + LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) { + LOGGER_INFO("coipil[%u]: switching ipv6 from %s:%u to %s:%u", i, + ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port), + ip_ntoa(&ip_port.ip), ntohs(ip_port.port)); + } + ); if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) return 1; @@ -251,10 +241,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t /* Initialize client timestamp. */ list[i].assoc4.timestamp = temp_time; memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); -#ifdef LOGGING - sprintf(logbuffer, "coipil[%u]: switching client_id (ipv4) \n", i); - loglog(logbuffer); -#endif + + LOGGER_DEBUG("coipil[%u]: switching client_id (ipv4)", i); + /* kill the other address, if it was set */ memset(&list[i].assoc6, 0, sizeof(list[i].assoc6)); return 1; @@ -262,10 +251,9 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t /* Initialize client timestamp. */ list[i].assoc6.timestamp = temp_time; memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); -#ifdef LOGGING - sprintf(logbuffer, "coipil[%u]: switching client_id (ipv6) \n", i); - loglog(logbuffer); -#endif + + LOGGER_DEBUG("coipil[%u]: switching client_id (ipv6)", i); + /* kill the other address, if it was set */ memset(&list[i].assoc4, 0, sizeof(list[i].assoc4)); return 1; @@ -469,18 +457,11 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request); if (!num_found) { -#ifdef LOGGING - loglog("get_close_nodes(): Assoc_get_close_entries() returned zero nodes.\n"); -#endif - + LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned zero nodes"); return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good); } - -#ifdef LOGGING - sprintf(logbuffer, "get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes.\n", - request.count_good, num_found - request.count_good); - loglog(logbuffer); -#endif + + LOGGER_DEBUG("get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes", request.count_good, num_found - request.count_good); uint8_t i, num_returned = 0; 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 \ ../toxcore/assoc.c \ ../toxcore/onion.h \ ../toxcore/onion.c \ + ../toxcore/logger.h \ + ../toxcore/logger.c \ ../toxcore/onion_announce.h \ ../toxcore/onion_announce.c \ ../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 @@ #include "config.h" #endif +#include "logger.h" #include "Messenger.h" #include "assoc.h" #include "network.h" @@ -2245,7 +2246,7 @@ void do_messenger(Messenger *m) #ifdef LOGGING if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { - loglog(" = = = = = = = = \n"); + #ifdef ENABLE_ASSOC_DHT Assoc_status(m->dht->assoc); #endif @@ -2254,12 +2255,10 @@ void do_messenger(Messenger *m) size_t c; for (c = 0; c < m->numchats; c++) { - loglog("---------------- \n"); Assoc_status(m->chats[c]->assoc); } } - loglog(" = = = = = = = = \n"); lastdump = unix_time(); uint32_t client, last_pinged; @@ -2276,14 +2275,12 @@ void do_messenger(Messenger *m) if (last_pinged > 999) last_pinged = 999; - snprintf(logbuffer, sizeof(logbuffer), "C[%2u] %s:%u [%3u] %s\n", - client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), - last_pinged, ID2String(cptr->client_id)); - loglog(logbuffer); + LOGGER_DEBUG("C[%2u] %s:%u [%3u] %s", + client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port), + last_pinged, ID2String(cptr->client_id)); } } - - loglog(" = = = = = = = = \n"); + uint32_t friend, dhtfriend; @@ -2311,9 +2308,7 @@ void do_messenger(Messenger *m) dht2m[m2dht[friend]] = friend; if (m->numfriends != m->dht->num_friends) { - sprintf(logbuffer, "Friend num in DHT %u != friend num in msger %u\n", - m->dht->num_friends, m->numfriends); - loglog(logbuffer); + LOGGER_DEBUG("Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); } uint32_t ping_lastrecv; @@ -2334,14 +2329,11 @@ void do_messenger(Messenger *m) if (ping_lastrecv > 999) ping_lastrecv = 999; - snprintf(logbuffer, sizeof(logbuffer), "F[%2u:%2u] <%s> %02i [%03u] %s\n", - dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, - ping_lastrecv, ID2String(msgfptr->client_id)); - loglog(logbuffer); + LOGGER_DEBUG("F[%2u:%2u] <%s> %02i [%03u] %s", + dht2m[friend], friend, msgfptr->name, msgfptr->crypt_connection_id, + ping_lastrecv, ID2String(msgfptr->client_id)); } else { - snprintf(logbuffer, sizeof(logbuffer), "F[--:%2u] %s\n", - friend, ID2String(dhtfptr->client_id)); - loglog(logbuffer); + LOGGER_DEBUG("F[--:%2u] %s", friend, ID2String(dhtfptr->client_id)); } for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { @@ -2355,20 +2347,16 @@ void do_messenger(Messenger *m) if (last_pinged > 999) last_pinged = 999; - - snprintf(logbuffer, sizeof(logbuffer), "F[%2u] => C[%2u] %s:%u [%3u] %s\n", - friend, client, ip_ntoa(&assoc->ip_port.ip), - ntohs(assoc->ip_port.port), last_pinged, - ID2String(cptr->client_id)); - loglog(logbuffer); + + LOGGER_DEBUG("F[%2u] => C[%2u] %s:%u [%3u] %s", + friend, client, ip_ntoa(&assoc->ip_port.ip), + ntohs(assoc->ip_port.port), last_pinged, + ID2String(cptr->client_id)); } } } - - loglog(" = = = = = = = = \n"); } - -#endif +#endif /* LOGGING */ } /* 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 @@ #include "config.h" #endif +#include "logger.h" #include "DHT.h" #include "assoc.h" #include "ping.h" @@ -524,9 +525,7 @@ static void client_id_self_update(Assoc *assoc) assoc->self_hash = id_hash(assoc, assoc->self_client_id); } -#ifdef LOGGING - loglog("assoc: id is now set, purging cache of self-references...\n"); -#endif + LOGGER_DEBUG("id is now set, purging cache of self-references"); /* if we already added some (or loaded some) entries, * 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) entries_test = prime_upto_min9(entries_test - 1); if (entries_test != entries) { -#ifdef LOGGING - sprintf(logbuffer, "new_Assoc(): trimmed %i to %i.\n", (int)entries, (int)entries_test); - loglog(logbuffer); -#endif + + LOGGER_DEBUG("trimmed %i to %i.\n", (int)entries, (int)entries_test); entries = (size_t)entries_test; } } @@ -873,7 +870,7 @@ void Assoc_self_client_id_changed(Assoc *assoc, uint8_t *id) #ifdef LOGGING static char *idpart2str(uint8_t *id, size_t len); -#endif +#endif /* LOGGING */ /* refresh buckets */ void do_Assoc(Assoc *assoc, DHT *dht) @@ -929,53 +926,30 @@ void do_Assoc(Assoc *assoc, DHT *dht) break; } -#ifdef LOGGING - size_t total = 0, written = sprintf(logbuffer, "assoc: [%u] => ", - (uint32_t)(candidate % assoc->candidates_bucket_count)); - - if (written > 0) - total += written; - -#endif - if (seen) { IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6; -#ifdef LOGGING - written = sprintf(logbuffer + total, " S[%s...] %s:%u", idpart2str(seen->client.client_id, 8), - ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port)); - - if (written > 0) - total += written; - -#endif + + LOGGER_DEBUG("[%u] => S[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count), + idpart2str(seen->client.client_id, 8), ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port)); + DHT_getnodes(dht, &ippts->ip_port, seen->client.client_id, target_id); seen->getnodes = unix_time(); } if (heard && (heard != seen)) { IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6; -#ifdef LOGGING - written = sprintf(logbuffer + total, " H[%s...] %s:%u", idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), - htons(ipp->port)); - - if (written > 0) - total += written; - -#endif + + LOGGER_DEBUG("[%u] => H[%s...] %s:%u", (uint32_t)(candidate % assoc->candidates_bucket_count), + idpart2str(heard->client.client_id, 8), ip_ntoa(&ipp->ip), htons(ipp->port)); + DHT_getnodes(dht, ipp, heard->client.client_id, target_id); heard->getnodes = unix_time(); } - -#ifdef LOGGING - - if (!heard && !seen) - sprintf(logbuffer + total, "no nodes to talk to??\n"); - else - /* for arcane reasons, sprintf(str, "\n") doesn't function */ - sprintf(logbuffer + total, "%s", "\n"); - - loglog(logbuffer); -#endif + + LOGGER_SCOPE ( + if ( !heard && !seen ) + LOGGER_DEBUG("[%u] => no nodes to talk to??", (uint32_t)(candidate % assoc->candidates_bucket_count)); + ); } } @@ -1009,11 +983,11 @@ static char *idpart2str(uint8_t *id, size_t len) void Assoc_status(Assoc *assoc) { if (!assoc) { - loglog("Assoc status: no assoc\n"); + LOGGER_INFO("Assoc status: no assoc"); return; } - - loglog("[b:p] hash => [id...] used, seen, heard\n"); + + LOGGER_INFO("[b:p] hash => [id...] used, seen, heard"); size_t bid, cid, total = 0; @@ -1024,24 +998,23 @@ void Assoc_status(Assoc *assoc) Client_entry *entry = &bucket->list[cid]; if (entry->hash) { - sprintf(logbuffer, "[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n", - (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8), - entry->used_at ? (int)(unix_time() - entry->used_at) : 0, - entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0, - entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?', + total++; + + LOGGER_INFO("[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\n", + (int)bid, (int)cid, entry->hash, idpart2str(entry->client.client_id, 8), + entry->used_at ? (int)(unix_time() - entry->used_at) : 0, + entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0, + entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?', entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0, entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?'); - loglog(logbuffer); - total++; } } } if (total) { - sprintf(logbuffer, "Total: %i entries, table usage %i%%.\n", (int)total, - (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); - loglog(logbuffer); + LOGGER_INFO("Total: %i entries, table usage %i%%.\n", (int)total, + (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size))); } } -#endif +#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); #ifdef LOGGING void Assoc_status(Assoc *assoc); -#endif +#endif /* LOGGING */ #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 @@ +/* logger.c + * + * Wrapping logger functions in nice macros + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + + +#include "logger.h" + +#ifdef LOGGING + +#include "network.h" /* for time */ + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) +#endif + +static struct logger_config { + FILE* log_file; + LoggerLevel level; + uint64_t start_time; /* Time when lib loaded */ +} +logger = { + NULL, + DEBUG, + 0 +}; + +void __attribute__((destructor)) terminate_logger() +{ + if ( !logger.log_file ) return; + + time_t tim = time(NULL); + + logger_write(ERROR, "============== Closing logger ==============\n" + "Time: %s", asctime(localtime(&tim))); + + fclose(logger.log_file); +} + +unsigned logger_get_pid() +{ + return + #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + GetCurrentProcessId(); + #else + getpid(); + #endif +} + +const char* logger_stringify_level(LoggerLevel level) +{ + static const char* strings [] = + { + "INFO", + "DEBUG", + "WARNING", + "ERROR" + }; + + return strings[level]; +} + + +int logger_init(const char* file_name, LoggerLevel level) +{ + char* final_l = calloc(sizeof(char), strlen(file_name) + 32); + sprintf(final_l, "%s"/*.%u"*/, file_name, logger_get_pid()); + + if ( logger.log_file ) { + fprintf(stderr, "Error opening logger name: %s with level %d: already opened!\n", final_l, level); + free (final_l); + return -1; + } + + logger.log_file = fopen(final_l, "wb"); + + if ( logger.log_file == NULL ) { + char error[1000]; + if ( strerror_r(errno, error, 1000) == 0 ) + fprintf(stderr, "Error opening logger file: %s; info: %s\n", final_l, error); + else + fprintf(stderr, "Error opening logger file: %s\n", final_l); + + free (final_l); + return -1; + } + + + logger.level = level; + logger.start_time = current_time(); + + + time_t tim = time(NULL); + logger_write(ERROR, "============== Starting logger ==============\n" + "Time: %s", asctime(localtime(&tim))); + + + + free (final_l); + return 0; +} + + +void logger_write (LoggerLevel level, const char* format, ...) +{ + if (logger.log_file == NULL) { + /*fprintf(stderr, "Logger file is NULL!\n");*/ + return; + } + + if (logger.level > level) return; /* Don't print some levels xuh */ + + va_list _arg; + va_start (_arg, format); + vfprintf (logger.log_file, format, _arg); + va_end (_arg); + + fflush(logger.log_file); +} + +char* logger_timestr(char* dest) +{ + uint64_t diff = (current_time() - logger.start_time) / 1000; /* ms */ + sprintf(dest, "%"PRIu64"", diff); + + return dest; +} + + +#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 @@ +/* logger.h + * + * Wrapping logger functions in nice macros + * + * Copyright (C) 2013 Tox project All Rights Reserved. + * + * This file is part of Tox. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + * + */ + + +#ifndef __TOXLOGGER +#define __TOXLOGGER + +// #define LOGGING + +#ifdef LOGGING +#include + +typedef enum _LoggerLevel +{ + INFO, + DEBUG, + WARNING, + ERROR +} LoggerLevel; + +/* + * Set 'level' as the lowest printable level + */ +int logger_init(const char* file_name, LoggerLevel level); +const char* logger_stringify_level(LoggerLevel level); +unsigned logger_get_pid(); +void logger_write (LoggerLevel level, const char* format, ...); +char* logger_timestr (char* dest); + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#define _SFILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#else +#define _SFILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#endif + +#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", \ + logger_get_pid(), logger_stringify_level(__LEVEL__), logger_timestr(__time__), _SFILE, __LINE__, __func__, format) + +/* Use these macros */ + +#define LOGGER_INIT(name, level) logger_init(name, level); +#define LOGGER_INFO(format, ...) do { char __time__[20]; WRITE_FORMAT(INFO, format); logger_write( INFO, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_DEBUG(format, ...) do { char __time__[20]; WRITE_FORMAT(DEBUG, format); logger_write( DEBUG, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_WARNING(format, ...) do { char __time__[20]; WRITE_FORMAT(WARNING, format); logger_write( WARNING, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) +#define LOGGER_ERROR(format, ...) do { char __time__[20]; WRITE_FORMAT(ERROR, format); logger_write( ERROR, the_str, ##__VA_ARGS__ ); free(the_str); } while (0) + +/* To do some checks or similar only when logging use this */ +#define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0) + +#else + + +#define LOGGER_INIT(name, level) +#define LOGGER_INFO(format, ...) +#define LOGGER_DEBUG(format, ...) +#define LOGGER_WARNING(format, ...) +#define LOGGER_ERROR(format, ...) + +#define LOGGER_SCOPE(__SCOPE_DO__) + +#endif /* LOGGING */ + + + + +#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 @@ #include "config.h" #endif +#define LOGGING +#include "logger.h" + #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) #include #endif @@ -205,9 +208,32 @@ uint64_t random_64b(void) return randnum; } -#ifdef LOGGING -static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res); -#endif +/* In case no logging */ +#ifndef LOGGING + +#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) + +#else + +#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0 +#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0 + +#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \ + (__ip_port__) .ip; \ + if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \ + LOGGER_INFO("[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", \ + __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \ + ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ + else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \ + LOGGER_INFO("[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", \ + __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \ + ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \ + else /* empty or overwrite */ \ + LOGGER_INFO("[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", \ + __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \ + ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, "OK", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); + +#endif /* LOGGING */ /* Basic network functions: * 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 } int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize); -#ifdef LOGGING - loglogdata("O=>", data, length, &ip_port, res); -#endif + + loglogdata("O=>", data, length, ip_port, res); + if ((res >= 0) && ((uint32_t)res == length)) net->send_fail_eagain = 0; @@ -297,14 +323,10 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); if (fail_or_len <= 0) { -#ifdef LOGGING - - if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) { - sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); - loglog(logbuffer); - } - -#endif + + LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK)) + LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); ); + return -1; /* Nothing received or empty packet. */ } @@ -329,9 +351,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t } else return -1; -#ifdef LOGGING - loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length); -#endif + loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length); return 0; } @@ -354,10 +374,7 @@ void networking_poll(Networking_Core *net) if (length < 1) continue; if (!(net->packethandlers[data[0]].function)) { -#ifdef LOGGING - sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]); - loglog(logbuffer); -#endif + LOGGER_WARNING("[%02u] -- Packet has no handler.\n", data[0]); continue; } @@ -460,22 +477,14 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds) timeout.tv_usec = microseconds; } -#ifdef LOGGING - errno = 0; -#endif /* returns -1 on error, 0 on timeout, the socket on activity */ int res = select(nfds, &readfds, &writefds, &exceptfds, timeout_ptr); -#ifdef LOGGING - - /* only dump if not timeout */ - if (res) { - sprintf(logbuffer, "select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno, - strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds), - FD_ISSET(s->sock, &exceptfds)); - loglog(logbuffer); - } - -#endif + + LOGGER_SCOPE( + if (res) LOGGER_INFO("select(%d, %d): %d (%d, %s) - %d %d %d\n", microseconds, seconds, res, errno, + strerror(errno), FD_ISSET(s->sock, &readfds), FD_ISSET(s->sock, &writefds), + FD_ISSET(s->sock, &exceptfds)); + ); if (FD_ISSET(s->sock, &writefds)) { s->send_fail_reset = 1; @@ -628,20 +637,12 @@ Networking_Core *new_networking(IP ip, uint16_t port) } if (ip.family == AF_INET6) { + #ifdef LOGGING - int is_dualstack = -#endif - set_socket_dualstack(temp->sock); -#ifdef LOGGING - - if (is_dualstack) { - loglog("Dual-stack socket: enabled.\n"); - } else { - loglog("Dual-stack socket: Failed to enable, won't be able to receive from/send to IPv4 addresses.\n"); - } - -#endif - + int is_dualstack = +#endif /* LOGGING */ + set_socket_dualstack(temp->sock); + LOGGER_DEBUG( "Dual-stack socket: %s", is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses" ); /* multicast local nodes */ struct ipv6_mreq mreq; memset(&mreq, 0, sizeof(mreq)); @@ -649,21 +650,13 @@ Networking_Core *new_networking(IP ip, uint16_t port) mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; mreq.ipv6mr_interface = 0; + #ifdef LOGGING - errno = 0; int res = -#endif - setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); -#ifdef LOGGING - - if (res < 0) { - sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n", - errno, strerror(errno)); - loglog(logbuffer); - } else - loglog("Local multicast group FF02::1 joined successfully.\n"); - -#endif +#endif /* LOGGING */ + setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); + + LOGGER_DEBUG(res < 0 ? "Failed to activate local multicast membership. (%u, %s)" : "Local multicast group FF02::1 joined successfully", errno, strerror(errno) ); } /* 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) if (!res) { temp->port = *portptr; -#ifdef LOGGING - loginit(temp->port); - - sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port)); - loglog(logbuffer); -#endif - + + LOGGER_DEBUG("Bound successfully to %s:%u", ip_ntoa(&ip), ntohs(temp->port)); + /* errno isn't reset on success, only set on failure, the failed * binds with parallel clients yield a -EPERM to the outside if * errno isn't cleared here */ @@ -1038,31 +1027,3 @@ int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) return 1; }; - -#ifdef LOGGING -static char errmsg_ok[3] = "OK"; -static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res) -{ - uint16_t port = ntohs(ip_port->port); - uint32_t data[2]; - data[0] = buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0; - data[1] = buflen > 7 ? ntohl(*(uint32_t *)&buffer[5]) : 0; - - /* Windows doesn't necessarily know %zu */ - if (res < 0) { - snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\n", - buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E', - ip_ntoa(&ip_port->ip), port, errno, strerror(errno), data[0], data[1]); - } else if ((res > 0) && ((size_t)res <= buflen)) - snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x\n", - buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='), - ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]); - else /* empty or overwrite */ - snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x\n", - buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen, - ip_ntoa(&ip_port->ip), port, 0, errmsg_ok, data[0], data[1]); - - logbuffer[sizeof(logbuffer) - 1] = 0; - loglog(logbuffer); -} -#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 @@ #endif #include "Messenger.h" +#include "logger.h" #define __TOX_DEFINED__ typedef struct Messenger Tox; @@ -773,6 +774,7 @@ int tox_isconnected(Tox *tox) */ Tox *tox_new(uint8_t ipv6enabled) { + LOGGER_INIT(LOGGER_OUTPUT_FILE, LOGGER_LEVEL); return new_messenger(ipv6enabled); } 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, return length == 0 ? 0 : -1; }; - -#ifdef LOGGING -time_t starttime = 0; -size_t logbufferprelen = 0; -char *logbufferpredata = NULL; -char *logbufferprehead = NULL; -char logbuffer[512]; -static FILE *logfile = NULL; -void loginit(uint16_t port) -{ - if (logfile) - fclose(logfile); - - if (!starttime) { - unix_time_update(); - starttime = unix_time(); - } - - struct tm *tm = localtime(&starttime); - - /* "%F %T" might not be Windows compatible */ - if (strftime(logbuffer + 32, sizeof(logbuffer) - 32, "%F %T", tm)) - sprintf(logbuffer, "%u-%s.log", ntohs(port), logbuffer + 32); - else - sprintf(logbuffer, "%u-%lu.log", ntohs(port), starttime); - - logfile = fopen(logbuffer, "w"); - - if (logbufferpredata) { - if (logfile) - fprintf(logfile, "%s", logbufferpredata); - - free(logbufferpredata); - logbufferpredata = NULL; - } - -}; -void loglog(char *text) -{ - if (logfile) { - fprintf(logfile, "%4u %s", (uint32_t)(unix_time() - starttime), text); - fflush(logfile); - - return; - } - - /* log messages before file was opened: store */ - - size_t len = strlen(text); - - if (!starttime) { - unix_time_update(); - starttime = unix_time(); - - logbufferprelen = 1024 + len - (len % 1024); - logbufferpredata = malloc(logbufferprelen); - logbufferprehead = logbufferpredata; - } - - /* loginit() called meanwhile? (but failed to open) */ - if (!logbufferpredata) - return; - - if (len + (logbufferprehead - logbufferpredata) + 16U < logbufferprelen) { - size_t logpos = logbufferprehead - logbufferpredata; - size_t lennew = logbufferprelen * 1.4; - logbufferpredata = realloc(logbufferpredata, lennew); - logbufferprehead = logbufferpredata + logpos; - logbufferprelen = lennew; - } - - int written = sprintf(logbufferprehead, "%4u %s", (uint32_t)(unix_time() - starttime), text); - logbufferprehead += written; -} - -void logexit() -{ - if (logfile) { - fclose(logfile); - logfile = NULL; - } -}; -#endif - 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 int load_state(load_state_callback_func load_state_callback, void *outer, uint8_t *data, uint32_t length, uint16_t cookie_inner); -#ifdef LOGGING -extern char logbuffer[512]; -void loginit(uint16_t port); -void loglog(char *text); -void logexit(); -#endif - #endif /* __UTIL_H__ */