diff --git a/toxav/phone.c b/toxav/phone.c new file mode 100755 index 00000000..b55a072c --- /dev/null +++ b/toxav/phone.c @@ -0,0 +1,737 @@ +/** phone.c + * + * NOTE NOTE NOTE NOTE NOTE NOTE + * + * This file is for testing/reference purposes only, hence + * it is _poorly_ designed and it does not fully reflect the + * quaility of msi nor rtp. Although toxmsi* and toxrtp* are tested + * there is always possiblity of crashes. If crash occures, + * contact me ( mannol ) on either irc channel #tox-dev @ freenode.net:6667 + * or eniz_vukovic@hotmail.com + * + * NOTE NOTE NOTE NOTE NOTE NOTE + * + * 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 */ + +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include +#include +#include + +#include "toxmsi.h" +#include "toxrtp.h" +#include +#include +#include + +#include "../toxcore/network.h" +#include "../toxcore/event.h" +#include "../toxcore/tox.h" + +/* Define client version */ +#define _USERAGENT "v.0.3.0" + + +typedef struct av_friend_s { + int _id; + int _active; /* 0=false; 1=true; */ +} av_friend_t; + +typedef struct av_session_s { + MSISession* _msi; + + RTPSession* _rtp_audio; + RTPSession* _rtp_video; + + pthread_mutex_t _mutex; + + Tox* _messenger; + av_friend_t* _friends; + int _friend_cout; + uint8_t _my_public_id[200]; +} av_session_t; + + +void av_allocate_friend(av_session_t* _phone, int _id, int _active) +{ + static int _new_id = 0; + + if ( !_phone->_friends ) { + _phone->_friends = calloc(sizeof(av_friend_t), 1); + _phone->_friend_cout = 1; + } else{ + _phone->_friend_cout ++; + _phone->_friends = realloc(_phone->_friends, sizeof(av_friend_t) * _phone->_friend_cout); + } + + if ( _id = -1 ) { + _phone->_friends->_id = _new_id; + _new_id ++; + } else _phone->_friends->_id = _id; + + _phone->_friends->_active = _active; +} +av_friend_t* av_get_friend(av_session_t* _phone, int _id) +{ + av_friend_t* _friends = _phone->_friends; + + if ( !_friends ) return NULL; + + int _it = 0; + for (; _it < _phone->_friend_cout; _it ++) + if ( _friends[_it]._id == _id ) + return _friends + _it; + + return NULL; +} + + +/***************** MISC *****************/ + +void INFO (const char* _format, ...) +{ + printf("\r[!] "); + va_list _arg; + va_start (_arg, _format); + vfprintf (stdout, _format, _arg); + va_end (_arg); + printf("\n\r >> "); + fflush(stdout); +} + +unsigned char *hex_string_to_bin(char hex_string[]) +{ + size_t i, len = strlen(hex_string); + unsigned char *val = calloc(sizeof(char), len); + char *pos = hex_string; + + for (i = 0; i < len; ++i, pos += 2) + sscanf(pos, "%2hhx", &val[i]); + + return val; +} + +int getinput( char* _buff, size_t _limit, int* _len ) +{ + if ( fgets(_buff, _limit, stdin) == NULL ) + return -1; + + *_len = strlen(_buff) - 1; + + /* Get rid of newline */ + _buff[*_len] = '\0'; + + return 0; +} + +char* trim_spaces ( char* buff ) +{ + + int _i = 0, _len = strlen(buff); + + char* container = calloc(sizeof(char), _len); + int _ci = 0; + + for ( ; _i < _len; _i++ ) { + while ( _i < _len && buff[_i] == ' ' ) + _i++; + + if ( _i < _len ){ + container[_ci] = buff[_i]; + _ci ++; + } + } + + memcpy( buff, container, _ci ); + buff[_ci] = '\0'; + free(container); + return buff; +} + +#define FRADDR_TOSTR_CHUNK_LEN 8 + +static void fraddr_to_str(uint8_t *id_bin, char *id_str) +{ + uint i, delta = 0, pos_extra, sum_extra = 0; + + for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) { + sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]); + + if ((i + 1) == TOX_CLIENT_ID_SIZE) + pos_extra = 2 * (i + 1) + delta; + + if (i >= TOX_CLIENT_ID_SIZE) + sum_extra |= id_bin[i]; + + if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) { + id_str[2 * (i + 1) + delta] = ' '; + delta++; + } + } + + id_str[2 * i + delta] = 0; + + if (!sum_extra) + id_str[pos_extra] = 0; +} + +void* phone_handle_media_transport_poll ( void* _hmtc_args_p ) +{ + RTPMessage* _audio_msg, * _video_msg; + av_session_t* _phone = _hmtc_args_p; + MSISession* _session = _phone->_msi; + + RTPSession* _rtp_audio = _phone->_rtp_audio; + RTPSession* _rtp_video = _phone->_rtp_video; + + + Tox* _messenger = _phone->_messenger; + + + while ( _session->call ) { + + _audio_msg = rtp_recv_msg ( _rtp_audio ); + _video_msg = rtp_recv_msg ( _rtp_video ); + + if ( _audio_msg ) { + /* Do whatever with msg + printf("%d - %s\n", _audio_msg->header->sequnum, _audio_msg->data);*/ + rtp_free_msg ( _rtp_audio, _audio_msg ); + } + + if ( _video_msg ) { + /* Do whatever with msg + p rintf("%d - %s\n", _video_msg->header->sequnum, _video_msg->data);*/ + rtp_free_msg ( _rtp_video, _video_msg ); + } + + /* + * Send test message to the 'remote' + */ + rtp_send_msg ( _rtp_audio, _messenger, (const uint8_t*)"audio\0", 6 ); + + if ( _session->call->type_local == type_video ){ /* if local call send video */ + rtp_send_msg ( _rtp_video, _messenger, (const uint8_t*)"video\0", 6 ); + } + + _audio_msg = _video_msg = NULL; + + + /* Send ~1k messages per second + * That _should_ be enough for both Audio and Video + */ + usleep ( 1000 ); + /* -------------------- */ + } + + if ( _audio_msg ) rtp_free_msg(_rtp_audio, _audio_msg); + rtp_release_session_recv(_rtp_audio); + rtp_terminate_session(_rtp_audio, _messenger); + + if ( _video_msg ) rtp_free_msg(_rtp_video, _video_msg); + rtp_release_session_recv(_rtp_video); + rtp_terminate_session(_rtp_video, _messenger); + + INFO("Media thread finished!"); + + pthread_exit ( NULL ); +} + +int phone_startmedia_loop ( av_session_t* _phone ) +{ + if ( !_phone ){ + return -1; + } + + _phone->_rtp_audio = rtp_init_session ( + type_audio, + _phone->_messenger, + _phone->_msi->call->peers[0], + _phone->_msi->call->key_peer, + _phone->_msi->call->key_local, + _phone->_msi->call->nonce_peer, + _phone->_msi->call->nonce_local + ); + + _phone->_rtp_audio = rtp_init_session ( + type_video, + _phone->_messenger, + _phone->_msi->call->peers[0], + _phone->_msi->call->key_peer, + _phone->_msi->call->key_local, + _phone->_msi->call->nonce_peer, + _phone->_msi->call->nonce_local + ); + + + if ( 0 > event.rise(phone_handle_media_transport_poll, _phone) ) + { + printf("Error while starting phone_handle_media_transport_poll()\n"); + return -1; + } + else return 0; +} + + +/* Some example callbacks */ + +void* callback_recv_invite ( void* _arg ) +{ + const char* _call_type; + + MSISession* _msi = _arg; + + switch ( _msi->call->type_peer[_msi->call->peer_count - 1] ){ + case type_audio: + _call_type = "audio"; + break; + case type_video: + _call_type = "video"; + break; + } + + INFO( "Incoming %s call!", _call_type ); + +} +void* callback_recv_ringing ( void* _arg ) +{ + INFO ( "Ringing!" ); +} +void* callback_recv_starting ( void* _arg ) +{ + MSISession* _session = _arg; + if ( 0 != phone_startmedia_loop(_session->agent_handler) ){ + INFO("Starting call failed!"); + } else { + INFO ("Call started! ( press h to hangup )"); + } +} +void* callback_recv_ending ( void* _arg ) +{ + INFO ( "Call ended!" ); +} + +void* callback_recv_error ( void* _arg ) +{ + MSISession* _session = _arg; + + INFO( "Error: %s", _session->last_error_str ); +} + +void* callback_call_started ( void* _arg ) +{ + MSISession* _session = _arg; + if ( 0 != phone_startmedia_loop(_session->agent_handler) ){ + INFO("Starting call failed!"); + } else { + INFO ("Call started! ( press h to hangup )"); + } + +} +void* callback_call_canceled ( void* _arg ) +{ + INFO ( "Call canceled!" ); +} +void* callback_call_rejected ( void* _arg ) +{ + INFO ( "Call rejected!" ); +} +void* callback_call_ended ( void* _arg ) +{ + INFO ( "Call ended!" ); +} + +void* callback_requ_timeout ( void* _arg ) +{ + INFO( "No answer! " ); +} + +int av_connect_to_dht(av_session_t* _phone, char* _dht_key, const char* _dht_addr, unsigned short _dht_port) +{ + unsigned char *_binary_string = hex_string_to_bin(_dht_key); + + uint16_t _port = htons(_dht_port); + + int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string ); + + free(_binary_string); + + return _if ? 0 : -1; +} + +av_session_t* av_init_session() +{ + av_session_t* _retu = malloc(sizeof(av_session_t)); + + /* Initialize our mutex */ + pthread_mutex_init ( &_retu->_mutex, NULL ); + + _retu->_messenger = tox_new(1); + + if ( !_retu->_messenger ) { + fprintf ( stderr, "tox_new() failed!\n" ); + return NULL; + } + + _retu->_friends = NULL; + + _retu->_rtp_audio = NULL; + _retu->_rtp_video = NULL; + + uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; + tox_get_address(_retu->_messenger, _byte_address ); + fraddr_to_str( _byte_address, _retu->_my_public_id ); + + + /* Initialize msi */ + _retu->_msi = msi_init_session ( _retu->_messenger, _USERAGENT ); + + if ( !_retu->_msi ) { + fprintf ( stderr, "msi_init_session() failed\n" ); + return NULL; + } + + _retu->_msi->agent_handler = _retu; + + /* ------------------ */ + msi_register_callback(callback_call_started, cb_onstart); + msi_register_callback(callback_call_canceled, cb_oncancel); + msi_register_callback(callback_call_rejected, cb_onreject); + msi_register_callback(callback_call_ended, cb_onend); + msi_register_callback(callback_recv_invite, cb_oninvite); + + msi_register_callback(callback_recv_ringing, cb_ringing); + msi_register_callback(callback_recv_starting, cb_starting); + msi_register_callback(callback_recv_ending, cb_ending); + + msi_register_callback(callback_recv_error, cb_error); + msi_register_callback(callback_requ_timeout, cb_timeout); + /* ------------------ */ + + return _retu; +} + +int av_terminate_session(av_session_t* _phone) +{ + if ( _phone->_msi->call ){ + msi_hangup(_phone->_msi); /* Hangup the phone first */ + } + + free(_phone->_friends); + msi_terminate_session(_phone->_msi); + pthread_mutex_destroy ( &_phone->_mutex ); + + Tox* _p = _phone->_messenger; + _phone->_messenger = NULL; usleep(100000); /* Wait for tox_pool to end */ + tox_kill(_p); + + printf("\r[i] Quit!\n"); + return 0; +} + +/****** AV HELPER FUNCTIONS ******/ + +/* Auto accept friend request */ +void av_friend_requ(uint8_t *_public_key, uint8_t *_data, uint16_t _length, void *_userdata) +{ + av_session_t* _phone = _userdata; + av_allocate_friend (_phone, -1, 0); + + INFO("Got friend request with message: %s", _data); + + tox_add_friend_norequest(_phone->_messenger, _public_key); + + INFO("Auto-accepted! Friend id: %d", _phone->_friends->_id ); +} + +void av_friend_active(Tox *_messenger, int _friendnumber, uint8_t *_string, uint16_t _length, void *_userdata) +{ + av_session_t* _phone = _userdata; + INFO("Friend no. %d is online", _friendnumber); + + av_friend_t* _this_friend = av_get_friend(_phone, _friendnumber); + + if ( !_this_friend ) { + INFO("But it's not registered!"); + return; + } + + (*_this_friend)._active = 1; +} + +int av_add_friend(av_session_t* _phone, char* _friend_hash) +{ + trim_spaces(_friend_hash); + + unsigned char *_bin_string = hex_string_to_bin(_friend_hash); + int _number = tox_add_friend(_phone->_messenger, _bin_string, (uint8_t *)"Tox phone "_USERAGENT, sizeof("Tox phone "_USERAGENT)); + free(_bin_string); + + if ( _number >= 0) { + INFO("Added friend as %d", _number ); + av_allocate_friend(_phone, _number, 0); + } + else + INFO("Unknown error %i", _number ); + + return _number; +} +/*********************************/ + +void do_phone ( av_session_t* _phone ) +{ + INFO("Welcome to tox_phone version: " _USERAGENT "\n" + "Usage: \n" + "f [pubkey] (add friend)\n" + "c [a/v] (type) [friend] (friend id) (calls friend if online)\n" + "h (if call is active hang up)\n" + "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n" + "r (reject incoming call)\n" + "q (quit)\n" + "================================================================================" + ); + + while ( 1 ) + { + char _line [ 1500 ]; + int _len; + + if ( -1 == getinput(_line, 1500, &_len) ){ + printf(" >> "); + fflush(stdout); + continue; + } + + if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ){ + INFO("Invalid input!"); + continue; + } + + switch (_line[0]){ + + case 'f': + { + char _id [128]; + strncpy(_id, _line + 2, 128); + + av_add_friend(_phone, _id); + + } break; + case 'c': + { + if ( _phone->_msi->call ){ + INFO("Already in a call"); + break; + } + + MSICallType _ctype; + + if ( _len < 5 ){ + INFO("Invalid input; usage: c a/v [friend]"); + break; + } + else if ( _line[2] == 'a' || _line[2] != 'v' ){ /* default and audio */ + _ctype = type_audio; + } + else { /* video */ + _ctype = type_video; + } + + char* _end; + int _friend = strtol(_line + 4, &_end, 10); + + if ( *_end ){ + INFO("Friend num has to be numerical value"); + break; + } + + /* Set timeout */ + msi_invite ( _phone->_msi, _ctype, 10 * 1000, _friend ); + INFO("Calling friend: %d!", _friend); + + } break; + case 'h': + { + if ( !_phone->_msi->call ){ + INFO("No call!"); + break; + } + + msi_hangup(_phone->_msi); + + INFO("Hung up..."); + + } break; + case 'a': + { + + if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ) { + break; + } + + if ( _len > 1 && _line[2] == 'v' ) + msi_answer(_phone->_msi, type_video); + else + msi_answer(_phone->_msi, type_audio); + + } break; + case 'r': + { + if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ){ + break; + } + + msi_reject(_phone->_msi); + + INFO("Call Rejected..."); + + } break; + case 'q': + { + INFO("Quitting!"); + return; + } + default: + { + INFO("Invalid command!"); + } break; + + } + + } +} + +void* tox_poll (void* _messenger_p) +{ + Tox** _messenger = _messenger_p; + while( *_messenger ) { + tox_do(*_messenger); + usleep(10000); + } + + pthread_exit(NULL); +} + +int av_wait_dht(av_session_t* _phone, int _wait_seconds, const char* _ip, char* _key, unsigned short _port) +{ + if ( !_wait_seconds ) + return -1; + + int _waited = 0; + + while( !tox_isconnected(_phone->_messenger) ) { + + if ( -1 == av_connect_to_dht(_phone, _key, _ip, _port) ) + { + INFO("Could not connect to: %s", _ip); + av_terminate_session(_phone); + return -1; + } + + if ( _waited >= _wait_seconds ) return 0; + + printf("."); + fflush(stdout); + + _waited ++; + usleep(1000000); + } + + int _r = _wait_seconds - _waited; + return _r ? _r : 1; +} +/* ---------------------- */ + +int print_help ( const char* _name ) +{ + printf ( "Usage: %s [IP] [PORT] [KEY]\n" + "\t[IP] (DHT ip)\n" + "\t[PORT] (DHT port)\n" + "\t[KEY] (DHT public key)\n" + "P.S. Friends and key are stored in ./tox_phone.conf\n" + ,_name ); + return 1; +} + +int main ( int argc, char* argv [] ) +{ + if ( argc < 1 || argc < 4 ) + return print_help(argv[0]); + + char* _convertable; + + int _wait_seconds = 5; + + const char* _ip = argv[1]; + char* _key = argv[3]; + unsigned short _port = strtol(argv[2], &_convertable, 10); + + if ( *_convertable ){ + printf("Invalid port: cannot convert string to long: %s", _convertable); + return 1; + } + + av_session_t* _phone = av_init_session(); + + tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone); + tox_callback_status_message(_phone->_messenger, av_friend_active, _phone); + + system("clear"); + + INFO("\r================================================================================\n" + "[!] Trying dht@%s:%d" + , _ip, _port); + + /* Start tox protocol */ + event.rise( tox_poll, &_phone->_messenger ); + + /* Just clean one line */ + printf("\r \r"); + fflush(stdout); + + int _r; + for ( _r = 0; _r == 0; _r = av_wait_dht(_phone, _wait_seconds, _ip, _key, _port) ) _wait_seconds --; + + + if ( -1 == _r ) { + INFO("Error while connecting to dht: %s:%d", _ip, _port); + av_terminate_session(_phone); + return 1; + } + + INFO("CONNECTED!\n" + "================================================================================\n" + "%s\n" + "================================================================================" + , _phone->_my_public_id ); + + + do_phone (_phone); + + av_terminate_session(_phone); + + return 0; +} diff --git a/toxmsi/toxmedia.c b/toxav/toxmedia.c similarity index 100% rename from toxmsi/toxmedia.c rename to toxav/toxmedia.c diff --git a/toxmsi/toxmedia.h b/toxav/toxmedia.h similarity index 98% rename from toxmsi/toxmedia.h rename to toxav/toxmedia.h index 8734b173..7eea39ae 100644 --- a/toxmsi/toxmedia.h +++ b/toxav/toxmedia.h @@ -70,7 +70,7 @@ #define DEFAULT_WEBCAM "/dev/video0" #endif -#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +#ifdef WIN32 #define VIDEO_DRIVER "vfwcap" #define DEFAULT_WEBCAM "0" #endif diff --git a/toxav/toxmsi.c b/toxav/toxmsi.c new file mode 100755 index 00000000..cf0914ab --- /dev/null +++ b/toxav/toxmsi.c @@ -0,0 +1,1337 @@ +/** toxmsi.c + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#define _BSD_SOURCE + +#include "toxmsi.h" +#include "../toxcore/util.h" +#include "../toxcore/network.h" +#include "../toxcore/event.h" +#include "../toxcore/Messenger.h" + +#include +#include +#include +#include + +#define same(x, y) strcmp((const char*) x, (const char*) y) == 0 + +#define MSI_MAXMSG_SIZE 1024 + +#define TYPE_REQUEST 1 +#define TYPE_RESPONSE 2 + +#define VERSION_STRING "0.3.1" +#define VERSION_STRLEN 5 + +#define CT_AUDIO_HEADER_VALUE "AUDIO" +#define CT_VIDEO_HEADER_VALUE "VIDEO" + + +/* Define default timeout for a request. + * There is no behavior specified by the msi on what will + * client do on timeout, but to call timeout callback. + */ +#define m_deftout 10000 /* in milliseconds */ + +/** + * Protocol: + * + * | desc. ( 1 byte ) | length ( 2 bytes ) | value ( length bytes ) | + * + * ie. + * + * | 0x1 | 0x0 0x7 | "version" + * + * Means: it's field value with length of 7 bytes and value of "version" + * It's similar to amp protocol + */ + + +#define GENERIC_HEADER(header) \ +typedef struct _MSIHeader##header { \ +uint8_t* header_value; \ +uint16_t size; \ +} MSIHeader##header; + + +GENERIC_HEADER ( Version ) +GENERIC_HEADER ( Request ) +GENERIC_HEADER ( Response ) +GENERIC_HEADER ( CallType ) +GENERIC_HEADER ( UserAgent ) +GENERIC_HEADER ( CallId ) +GENERIC_HEADER ( Info ) +GENERIC_HEADER ( Reason ) +GENERIC_HEADER ( CryptoKey ) +GENERIC_HEADER ( Nonce ) + + +/** + * @brief This is the message structure. It contains all of the headers and + * destination/source of the message stored in friend_id. + * + */ +typedef struct _MSIMessage { + + MSIHeaderVersion version; + MSIHeaderRequest request; + MSIHeaderResponse response; + MSIHeaderCallType calltype; + MSIHeaderUserAgent useragent; + MSIHeaderInfo info; + MSIHeaderReason reason; + MSIHeaderCallId callid; + MSIHeaderCryptoKey cryptokey; + MSIHeaderNonce nonce; + + struct _MSIMessage* next; + + int friend_id; + +} MSIMessage; + + + +static MSICallback callbacks[9] = {0}; + + +/* define strings for the identifiers */ +#define VERSION_FIELD "Version" +#define REQUEST_FIELD "Request" +#define RESPONSE_FIELD "Response" +#define INFO_FIELD "INFO" +#define REASON_FIELD "Reason" +#define CALLTYPE_FIELD "Call-type" +#define USERAGENT_FIELD "User-agent" +#define CALLID_FIELD "Call-id" +#define CRYPTOKEY_FIELD "Crypto-key" +#define NONCE_FIELD "Nonce" + +/* protocol descriptors */ +#define end_byte 0x0 +#define field_byte 0x1 +#define value_byte 0x2 + + +typedef enum { + invite, + start, + cancel, + reject, + end, + +} MSIRequest; + + +/** + * @brief Get string value for request. + * + * @param request The request. + * @return const uint8_t* The string + */ +static inline const uint8_t *stringify_request ( MSIRequest request ) { + static const uint8_t* strings[] = { + ( uint8_t* ) "INVITE", + ( uint8_t* ) "START", + ( uint8_t* ) "CANCEL", + ( uint8_t* ) "REJECT", + ( uint8_t* ) "END" + }; + + return strings[request]; +} + + +typedef enum { + ringing, + starting, + ending, + error + +} MSIResponse; + + +/** + * @brief Get string value for response. + * + * @param response The response. + * @return const uint8_t* The string + */ +static inline const uint8_t *stringify_response ( MSIResponse response ) { + static const uint8_t* strings[] = { + ( uint8_t* ) "ringing", + ( uint8_t* ) "starting", + ( uint8_t* ) "ending", + ( uint8_t* ) "error" + }; + + return strings[response]; +} + + +#define ON_HEADER(iterator, header, descriptor, size_const) \ +( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \ + iterator += size_const; /* Set iterator at begining of value part */ \ + if ( *iterator != value_byte ) { assert(0); return -1; }\ + iterator ++;\ + uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \ + (uint16_t) *(iterator + 1); \ + header.header_value = calloc(sizeof(uint8_t), _value_size); \ + header.size = _value_size; \ + memcpy(header.header_value, iterator + 2, _value_size);\ + iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ \ +} + +/** + * @brief Parse raw 'data' received from socket into MSIMessage struct. + * Every message has to have end value of 'end_byte' or _undefined_ behavior + * occures. The best practice is to check the end of the message at the handle_packet. + * + * @param msg Container. + * @param data The data. + * @return int + * @retval -1 Error occured. + * @retval 0 Success. + */ +int parse_raw_data ( MSIMessage* msg, const uint8_t* data ) { + assert ( msg ); + + const uint8_t* _it = data; + + while ( *_it ) {/* until end_byte is hit */ + + if ( *_it == field_byte ) { + uint16_t _size = ( uint16_t ) * ( _it + 1 ) << 8 | + ( uint16_t ) * ( _it + 2 ); + + _it += 3; /*place it at the field value beginning*/ + + switch ( _size ) { /* Compare the size of the hardcoded values ( vary fast and convenient ) */ + + case 4: { /* INFO header */ + if ON_HEADER ( _it, msg->info, INFO_FIELD, 4 ) + } + break; + + case 5: { /* NONCE header */ + if ON_HEADER ( _it, msg->nonce, NONCE_FIELD, 5 ) + } + break; + + case 6: { /* Reason header */ + if ON_HEADER ( _it, msg->reason, REASON_FIELD, 6 ) + } + break; + + case 7: { /* Version, Request, Call-id headers */ + 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 */ + if ON_HEADER ( _it, msg->response, RESPONSE_FIELD, 8 ) + } + break; + + case 9: { /* Call-type header */ + if ON_HEADER ( _it, msg->calltype, CALLTYPE_FIELD, 9 ) + } + break; + + case 10: { /* User-agent, Crypto-key headers */ + if ON_HEADER ( _it, msg->useragent, USERAGENT_FIELD, 10 ) + else if ON_HEADER ( _it, msg->cryptokey, CRYPTOKEY_FIELD, 10 ) + } + break; + + default: + return -1; + } + } else return -1; + /* If it's anything else return failure as the message is invalid */ + + } + + return 0; +} + + +#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; + + +/** + * @brief Speaks for it self. + * + * @param msg The message. + * @return void + */ +void free_message ( MSIMessage* msg ) { + assert ( msg ); + + free ( msg->calltype.header_value ); + free ( msg->request.header_value ); + free ( msg->response.header_value ); + free ( msg->useragent.header_value ); + free ( msg->version.header_value ); + free ( msg->info.header_value ); + free ( msg->cryptokey.header_value ); + free ( msg->nonce.header_value ); + free ( msg->reason.header_value ); + free ( msg->callid.header_value ); + + free ( msg ); +} + + +/** + * @brief Create the message. + * + * @param type Request or response. + * @param type_id Type of request/response. + * @return MSIMessage* Created message. + * @retval NULL Error occured. + */ +MSIMessage* msi_new_message ( uint8_t type, const uint8_t* type_id ) { + MSIMessage* _retu = calloc ( sizeof ( MSIMessage ), 1 ); + assert ( _retu ); + + memset ( _retu, 0, sizeof ( MSIMessage ) ); + + if ( type == TYPE_REQUEST ) { + ALLOCATE_HEADER ( _retu->request, type_id, strlen ( type_id ) ) + + } else if ( type == TYPE_RESPONSE ) { + ALLOCATE_HEADER ( _retu->response, type_id, strlen ( type_id ) ) + + } else { + free_message ( _retu ); + return NULL; + } + + ALLOCATE_HEADER ( _retu->version, VERSION_STRING, strlen ( VERSION_STRING ) ) + + return _retu; +} + + +/** + * @brief Parse data from handle_packet. + * + * @param data The data. + * @return MSIMessage* Parsed message. + * @retval NULL Error occured. + */ +MSIMessage* parse_message ( const uint8_t* data ) { + assert ( data ); + + MSIMessage* _retu = calloc ( sizeof ( MSIMessage ), 1 ); + assert ( _retu ); + + memset ( _retu, 0, sizeof ( MSIMessage ) ); + + if ( parse_raw_data ( _retu, data ) == -1 ) { + + free_message ( _retu ); + return NULL; + } + + if ( !_retu->version.header_value || VERSION_STRLEN != _retu->version.size || + memcmp ( _retu->version.header_value, VERSION_STRING, VERSION_STRLEN ) != 0 ) { + + free_message ( _retu ); + return NULL; + } + + return _retu; +} + + + +/** + * @brief Speaks for it self. + * + * @param dest Container. + * @param header_field Field. + * @param header_value Field value. + * @param value_len Length of field value. + * @param length Pointer to container length. + * @return uint8_t* Iterated container. + */ +uint8_t* append_header_to_string ( + uint8_t* dest, + const uint8_t* header_field, + const uint8_t* header_value, + uint16_t value_len, + uint16_t* length ) +{ + assert ( dest ); + assert ( header_value ); + assert ( header_field ); + + const uint8_t* _hvit = header_value; + uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ + + *dest = field_byte; /* Set the first byte */ + + uint8_t* _getback_byte = dest + 1; /* remeber the byte we were on */ + dest += 3; /* swith to 4th byte where field value starts */ + + /* Now set the field value and calculate it's length */ + uint16_t _i = 0; + for ( ; header_field[_i]; ++_i ) { + *dest = header_field[_i]; + ++dest; + }; + _total += _i; + + /* Now set the length of the field byte */ + *_getback_byte = ( uint8_t ) _i >> 8; + _getback_byte++; + *_getback_byte = ( uint8_t ) _i; + + /* for value part do it regulary */ + *dest = value_byte; + dest++; + + *dest = ( uint8_t ) value_len >> 8; + dest++; + *dest = ( uint8_t ) value_len; + dest++; + + for ( _i = value_len; _i; --_i ) { + *dest = *_hvit; + ++_hvit; + ++dest; + } + + *length += _total; + return dest; +} + + +#define CLEAN_ASSIGN(added, var, field, header)\ +if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); } + + +/** + * @brief Convert MSIMessage struct to _sendable_ string. + * + * @param msg The message. + * @param dest Destination. + * @return uint16_t It's final size. + */ +uint16_t message_to_string ( MSIMessage* msg, uint8_t* dest ) { + assert ( msg ); + assert ( dest ); + + uint8_t* _iterated = dest; + uint16_t _size = 0; + + CLEAN_ASSIGN ( _size, _iterated, VERSION_FIELD, msg->version ); + CLEAN_ASSIGN ( _size, _iterated, REQUEST_FIELD, msg->request ); + CLEAN_ASSIGN ( _size, _iterated, RESPONSE_FIELD, msg->response ); + CLEAN_ASSIGN ( _size, _iterated, CALLTYPE_FIELD, msg->calltype ); + CLEAN_ASSIGN ( _size, _iterated, USERAGENT_FIELD, msg->useragent ); + CLEAN_ASSIGN ( _size, _iterated, INFO_FIELD, msg->info ); + CLEAN_ASSIGN ( _size, _iterated, CALLID_FIELD, msg->callid ); + CLEAN_ASSIGN ( _size, _iterated, REASON_FIELD, msg->reason ); + CLEAN_ASSIGN ( _size, _iterated, CRYPTOKEY_FIELD, msg->cryptokey ); + CLEAN_ASSIGN ( _size, _iterated, NONCE_FIELD, msg->nonce ); + + *_iterated = end_byte; + _size ++; + + return _size; +} + + +#define GENERIC_SETTER_DEFINITION(header) \ +void msi_msg_set_##header ( MSIMessage* _msg, const uint8_t* header_value, uint16_t _size ) \ +{ assert(_msg); assert(header_value); \ + free(_msg->header.header_value); \ + ALLOCATE_HEADER( _msg->header, header_value, _size )} + +GENERIC_SETTER_DEFINITION ( calltype ) +GENERIC_SETTER_DEFINITION ( useragent ) +GENERIC_SETTER_DEFINITION ( reason ) +GENERIC_SETTER_DEFINITION ( info ) +GENERIC_SETTER_DEFINITION ( callid ) +GENERIC_SETTER_DEFINITION ( cryptokey ) +GENERIC_SETTER_DEFINITION ( nonce ) + + +/** + * @brief Generate _random_ alphanumerical string. + * + * @param str Destination. + * @param size Size of string. + * @return void + */ +void t_randomstr ( uint8_t* str, size_t size ) { + assert ( str ); + + static const uint8_t _bytes[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + int _it = 0; + + for ( ; _it < size; _it++ ) { + str[_it] = _bytes[ randombytes_random() % 61 ]; + } +} + + +typedef enum { + error_deadcall = 1, /* has call id but it's from old call */ + error_id_mismatch, /* non-existing call */ + + error_no_callid, /* not having call id */ + error_no_call, /* no call in session */ + error_no_crypto_key, /* no crypto key */ + + error_busy, + +} MSICallError; /* Error codes */ + + +/** + * @brief Stringify error code. + * + * @param error_code The code. + * @return const uint8_t* The string. + */ +static inline const uint8_t *stringify_error ( MSICallError error_code ) { + static const uint8_t* strings[] = { + ( uint8_t* ) "", + ( uint8_t* ) "Using dead call", + ( uint8_t* ) "Call id not set to any call", + ( uint8_t* ) "Call id not available", + ( uint8_t* ) "No active call in session", + ( uint8_t* ) "No Crypto-key set", + ( uint8_t* ) "Callee busy" + }; + + return strings[error_code]; +} + + +/** + * @brief Convert error_code into string. + * + * @param error_code The code. + * @return const uint8_t* The string. + */ +static inline const uint8_t *stringify_error_code ( MSICallError error_code ) { + static const uint8_t* strings[] = { + ( uint8_t* ) "", + ( uint8_t* ) "1", + ( uint8_t* ) "2", + ( uint8_t* ) "3", + ( uint8_t* ) "4", + ( uint8_t* ) "5", + ( uint8_t* ) "6" + }; + + return strings[error_code]; +} + + +/** + * @brief Speaks for it self. + * + * @param session Control session. + * @param msg The message. + * @param to Where to. + * @return int + * @retval -1 Error occured. + * @retval 0 Success. + */ +int send_message ( MSISession* session, MSIMessage* msg, uint32_t to ) +{ + msi_msg_set_callid ( msg, session->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((struct Messenger*) session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; +} + + +/** + * @brief Speaks for it self. + * + * @param session Control session. + * @param msg The message. + * @param peer_id The peer. + * @return void + */ +void flush_peer_type ( MSISession* session, MSIMessage* msg, int peer_id ) { + if ( msg->calltype.header_value ) { + if ( strcmp ( ( const char* ) msg->calltype.header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) { + session->call->type_peer[peer_id] = type_audio; + + } else if ( strcmp ( ( const char* ) msg->calltype.header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) { + session->call->type_peer[peer_id] = type_video; + } else {} /* Error */ + } else {} /* Error */ +} + + + +/** + * @brief Sends error response to peer. + * + * @param session The session. + * @param errid The id. + * @param to Where to? + * @return int + * @retval 0 It's always success. + */ +int handle_error ( MSISession* session, MSICallError errid, uint32_t to ) { + 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 ); + free_message ( _msg_error ); + + session->last_error_id = errid; + session->last_error_str = stringify_error ( errid ); + + event.rise ( callbacks[cb_error], session ); + + return 0; +} + + +/** + * @brief Determine the error if any. + * + * @param session Control session. + * @param msg The message. + * @return int + * @retval -1 No error. + * @retval 0 Error occured and response sent. + */ +int has_call_error ( MSISession* session, MSIMessage* msg ) { + if ( !msg->callid.header_value ) { + return handle_error ( session, error_no_callid, msg->friend_id ); + + } else if ( !session->call ) { + return handle_error ( session, 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 ); + + } + + return -1; +} + + +/** + * @brief Function called at request timeout. + * + * @param arg Control session + * @return void* + */ +void* handle_timeout ( void* arg ) +{ + /* Send hangup either way */ + MSISession* _session = arg; + + uint32_t* _peers = _session->call->peers; + uint16_t _peer_count = _session->call->peer_count; + + + /* Cancel all? */ + uint16_t _it = 0; + for ( ; _it < _peer_count; _it++ ) + msi_cancel ( arg, _peers[_it] ); + + + ( *callbacks[cb_timeout] ) ( arg ); + ( *callbacks[cb_ending ] ) ( arg ); + + return NULL; +} + + +/** + * @brief Add peer to peer list. + * + * @param call What call. + * @param peer_id Its id. + * @return void + */ +void add_peer( MSICall* call, int peer_id ) +{ + if ( !call->peers ) { + call->peers = calloc(sizeof(int), 1); + call->peer_count = 1; + } else{ + call->peer_count ++; + call->peers = realloc( call->peers, sizeof(int) * call->peer_count); + } + + call->peers[call->peer_count - 1] = peer_id; +} + + +/** + * @brief BASIC call flow: + * + * ALICE BOB + * | invite --> | + * | | + * | <-- ringing | + * | | + * | <-- starting | + * | | + * | start --> | + * | | + * | <-- MEDIA TRANS --> | + * | | + * | end --> | + * | | + * | <-- ending | + * + * Alice calls Bob by sending invite packet. + * Bob recvs the packet and sends an ringing packet; + * which notifies Alice that her invite is acknowledged. + * Ringing screen shown on both sides. + * Bob accepts the invite for a call by sending starting packet. + * Alice recvs the starting packet and sends the started packet to + * inform Bob that she recved the starting packet. + * Now the media transmission is established ( i.e. RTP transmission ). + * Alice hangs up and sends end packet. + * Bob recves the end packet and sends ending packet + * as the acknowledgement that the call is ending. + * + * + */ +void msi_handle_packet ( Messenger* messenger, int source, uint8_t* data, uint16_t length, void* object ) +{ + MSISession* _session = object; + MSIMessage* _msg; + + _msg = parse_message ( data ); + + if ( !_msg ) return; + + _msg->friend_id = source; + + + /* Now handle message */ + + if ( _msg->request.header_value ) { /* Handle request */ + + const uint8_t* _request_value = _msg->request.header_value; + + if ( same ( _request_value, stringify_request ( invite ) ) ) { + handle_recv_invite ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( start ) ) ) { + handle_recv_start ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { + handle_recv_cancel ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( reject ) ) ) { + handle_recv_reject ( _session, _msg ); + + } else if ( same ( _request_value, stringify_request ( end ) ) ) { + handle_recv_end ( _session, _msg ); + } + + else { + free_message ( _msg ); + return; + } + + } else if ( _msg->response.header_value ) { /* Handle response */ + + const uint8_t* _response_value = _msg->response.header_value; + + if ( same ( _response_value, stringify_response ( ringing ) ) ) { + handle_recv_ringing ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( starting ) ) ) { + handle_recv_starting ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( ending ) ) ) { + handle_recv_ending ( _session, _msg ); + + } else if ( same ( _response_value, stringify_response ( error ) ) ) { + handle_recv_error ( _session, _msg ); + } else { + free_message ( _msg ); + return; + } + + /* Got response so cancel timer */ + if ( _session->call ) + event.timer_release ( _session->call->request_timer_id ); + + } + + free_message ( _msg ); +} + + +/** + * @brief Speaks for it self. + * + * @param session Control session. + * @param peers Amount of peers. (Currently it only supports 1) + * @param ringing_timeout Ringing timeout. + * @return MSICall* The created call. + */ +MSICall* init_call ( MSISession* session, int peers, int ringing_timeout ) { + assert ( session ); + assert ( peers ); + + MSICall* _call = calloc ( sizeof ( MSICall ), 1 ); + _call->type_peer = calloc ( sizeof ( MSICallType ), peers ); + + assert ( _call ); + assert ( _call->type_peer ); + + /*_call->_participant_count = _peers;*/ + + _call->request_timer_id = 0; + _call->ringing_timer_id = 0; + + _call->key_local = NULL; + _call->key_peer = NULL; + _call->nonce_local = NULL; + _call->nonce_peer = NULL; + + _call->ringing_tout_ms = ringing_timeout; + + pthread_mutex_init ( &_call->mutex, NULL ); + + return _call; +} + + +/** + * @brief Terminate the call. + * + * @param session Control session. + * @return int + * @retval -1 Error occured. + * @retval 0 Success. + */ +int terminate_call ( MSISession* session ) { + assert ( session ); + + if ( !session->call ) + return -1; + + + /* Check event loop and cancel timed events if there are any + * Notice: 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 ); + + /* Get a handle */ + pthread_mutex_lock ( &session->call->mutex ); + + MSICall* _call = session->call; + session->call = NULL; + + free ( _call->type_peer ); + free ( _call->key_local ); + free ( _call->key_peer ); + free ( _call->peers); + + /* Release handle */ + pthread_mutex_unlock ( &_call->mutex ); + + pthread_mutex_destroy ( &_call->mutex ); + + free ( _call ); + + return 0; +} + + +/********** Request handlers **********/ +int handle_recv_invite ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( session->call ) { + handle_error ( session, error_busy, msg->friend_id ); + return 0; + } + if ( !msg->callid.header_value ) { + handle_error ( session, 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; + + add_peer( session->call, msg->friend_id); + + flush_peer_type ( session, msg, 0 ); + + MSIMessage* _msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); + send_message ( session, _msg_ringing, msg->friend_id ); + free_message ( _msg_ringing ); + + event.rise ( callbacks[cb_oninvite], session ); + + return 1; +} +int handle_recv_start ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + if ( !msg->cryptokey.header_value ) + return handle_error ( session, error_no_crypto_key, msg->friend_id ); + + session->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 ); + + session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); + memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); + + flush_peer_type ( session, msg, 0 ); + + event.rise ( callbacks[cb_onstart], session ); + + return 1; +} +int handle_recv_reject ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + + MSIMessage* _msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); + send_message ( session, _msg_end, msg->friend_id ); + free_message ( _msg_end ); + + event.timer_release ( session->call->request_timer_id ); + event.rise ( callbacks[cb_onreject], session ); + session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + + return 1; +} +int handle_recv_cancel ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + + terminate_call ( session ); + + event.rise ( callbacks[cb_oncancel], session ); + + return 1; +} +int handle_recv_end ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + + MSIMessage* _msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); + send_message ( session, _msg_ending, msg->friend_id ); + free_message ( _msg_ending ); + + terminate_call ( session ); + + event.rise ( callbacks[cb_onend], session ); + + return 1; +} + +/********** Response handlers **********/ +int handle_recv_ringing ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); + event.rise ( callbacks[cb_ringing], session ); + + return 1; +} +int handle_recv_starting ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + if ( !msg->cryptokey.header_value ) { + return handle_error ( session, 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 ); + + session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); + new_nonce ( session->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 ); + + session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); + memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); + + session->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_box_NONCEBYTES ); + send_message ( session, _msg_start, msg->friend_id ); + free_message ( _msg_start ); + + flush_peer_type ( session, msg, 0 ); + + event.rise ( callbacks[cb_starting], session ); + event.timer_release ( session->call->ringing_timer_id ); + + return 1; +} +int handle_recv_ending ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + + if ( has_call_error ( session, msg ) == 0 ) + return 0; + + + terminate_call ( session ); + + event.rise ( callbacks[cb_ending], session ); + + return 1; +} +int handle_recv_error ( MSISession* session, MSIMessage* msg ) { + assert ( session ); + assert ( session->call ); + + /* 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 ); + } + + terminate_call ( session ); + + event.rise ( callbacks[cb_ending], session ); + + return 1; +} + + +/******************************************************************************************************************** + * ******************************************************************************************************************* + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + * + * + * + * PUBLIC API FUNCTIONS IMPLEMENTATIONS + * + * + * + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ********************************************************************************************************************/ + + + + + + + + +/** + * @brief Callback setter. + * + * @param callback The callback. + * @param id The id. + * @return void + */ +void msi_register_callback ( MSICallback callback, MSICallbackID id ) +{ + callbacks[id] = callback; +} + + +/** + * @brief Start the control session. + * + * @param messenger Tox* object. + * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' + * @return MSISession* The created session. + * @retval NULL Error occured. + */ +MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ) { + assert ( messenger ); + assert ( user_agent ); + + MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); + assert ( _retu ); + + _retu->user_agent = user_agent; + _retu->messenger_handle = messenger; + _retu->agent_handler = NULL; + + _retu->call = NULL; + + _retu->frequ = 10000; /* default value? */ + _retu->call_timeout = 30000; /* default value? */ + + + m_callback_msi_packet((struct Messenger*) messenger, msi_handle_packet, _retu ); + + + return _retu; +} + + +/** + * @brief Terminate control session. + * + * @param session The session + * @return int + */ +int msi_terminate_session ( MSISession* session ) { + assert ( session ); + + int _status = 0; + + terminate_call ( session ); + + /* TODO: Clean it up more? */ + + free ( session ); + return _status; +} + + +/** + * @brief Send invite request to friend_id. + * + * @param session Control session. + * @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 ) { + assert ( session ); + + MSIMessage* _msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); + + session->call = init_call ( session, 1, rngsec ); /* Just one for now */ + t_randomstr ( session->call->id, CALL_ID_LEN ); + + add_peer(session->call, friend_id ); + + session->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 ) ); + } else { + 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 ); + free_message ( _msg_invite ); + + session->call->state = call_inviting; + + session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + + return 0; +} + + +/** + * @brief Hangup active call. + * + * @param session Control session. + * @return int + * @retval -1 Error occured. + * @retval 0 Success. + */ +int msi_hangup ( MSISession* session ) { + assert ( session ); + + if ( !session->call && session->call->state != call_active ) + return -1; + + MSIMessage* _msg_ending = 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_ending, session->call->peers[_it] ); + + + free_message ( _msg_ending ); + + session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + + return 0; +} + + +/** + * @brief Answer active call request. + * + * @param session Control session. + * @param call_type Answer with Audio or Video(both). + * @return int + */ +int msi_answer ( MSISession* session, MSICallType call_type ) { + assert ( session ); + + MSIMessage* _msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); + session->call->type_local = call_type; + + if ( call_type == type_audio ) { + msi_msg_set_calltype + ( _msg_starting, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); + } else { + msi_msg_set_calltype + ( _msg_starting, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) ); + } + + /* 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->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); + new_nonce ( session->call->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_box_NONCEBYTES ); + + send_message ( session, _msg_starting, session->call->peers[session->call->peer_count - 1] ); + free_message ( _msg_starting ); + + session->call->state = call_active; + + return 0; +} + + +/** + * @brief Cancel request. + * + * @param session Control session. + * @param friend_id The friend. + * @return int + */ +int msi_cancel ( MSISession* session, int friend_id ) { + assert ( session ); + + MSIMessage* _msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); + send_message ( session, _msg_cancel, friend_id ); + free_message ( _msg_cancel ); + + terminate_call ( session ); + + return 0; +} + + +/** + * @brief Reject request. + * + * @param session Control session. + * @return int + */ +int msi_reject ( MSISession* session ) { + assert ( session ); + + MSIMessage* _msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); + send_message ( session, _msg_reject, session->call->peers[session->call->peer_count - 1] ); + free_message ( _msg_reject ); + + session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); + + return 0; +} + + +/** + * @brief Terminate the current call. + * + * @param session Control session. + * @return int + */ +int msi_stopcall ( MSISession* session ) { + assert ( session ); + + if ( !session->call ) + return -1; + + /* just terminate it */ + + terminate_call ( session ); + + return 0; +} \ No newline at end of file diff --git a/toxav/toxmsi.h b/toxav/toxmsi.h new file mode 100755 index 00000000..c45662a6 --- /dev/null +++ b/toxav/toxmsi.h @@ -0,0 +1,231 @@ +/** toxmsi.h + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + +#ifndef __TOXMSI +#define __TOXMSI + +#include +#include "../toxcore/tox.h" +#include + +/* define size for call_id */ +#define CALL_ID_LEN 12 + + +typedef void* ( *MSICallback ) ( void* arg ); + + +/** + * @brief Call type identifier. Also used as rtp callback prefix. + */ +typedef enum { + type_audio = 70, + type_video, +} MSICallType; + + +/** + * @brief Call state identifiers. + */ +typedef enum { + call_inviting, /* when sending call invite */ + call_starting, /* when getting call invite */ + call_active, + call_hold + +} MSICallState; + + + +/** + * @brief The call struct. + * + */ +typedef struct _MSICall { /* Call info structure */ + MSICallState state; + + 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* 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 */ + + 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; + + +} MSICall; + + +/** + * @brief Control session struct + * + */ +typedef struct _MSISession { + + /* Call handler */ + struct _MSICall* call; + + int last_error_id; /* Determine the last error */ + const uint8_t* last_error_str; + + const uint8_t* user_agent; + + void* agent_handler; /* Pointer to an object that is handling msi */ + Tox* messenger_handle; + + uint32_t frequ; + uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ + + +} MSISession; + + +/** + * @brief Callbacks ids that handle the states + */ +typedef enum { + /* Requests */ + cb_oninvite, + cb_onstart, + cb_oncancel, + cb_onreject, + cb_onend, + + /* Responses */ + cb_ringing, + cb_starting, + cb_ending, + + /* Protocol */ + cb_error, + cb_timeout, + +} MSICallbackID; + + +/** + * @brief Callback setter. + * + * @param callback The callback. + * @param id The id. + * @return void + */ +void msi_register_callback(MSICallback callback, MSICallbackID id); + + +/** + * @brief Start the control session. + * + * @param messenger Tox* object. + * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' + * @return MSISession* The created session. + * @retval NULL Error occured. + */ +MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ); + + +/** + * @brief Terminate control session. + * + * @param session The session + * @return int + */ +int msi_terminate_session ( MSISession* session ); + + +/** + * @brief Send invite request to friend_id. + * + * @param session Control session. + * @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 ); + + +/** + * @brief Hangup active call. + * + * @param session Control session. + * @return int + * @retval -1 Error occured. + * @retval 0 Success. + */ +int msi_hangup ( MSISession* session ); + + +/** + * @brief Answer active call request. + * + * @param session Control session. + * @param call_type Answer with Audio or Video(both). + * @return int + */ +int msi_answer ( MSISession* session, MSICallType call_type ); + + +/** + * @brief Cancel request. + * + * @param session Control session. + * @param friend_id The friend. + * @return int + */ +int msi_cancel ( MSISession* session, int friend_id ); + + +/** + * @brief Reject request. + * + * @param session Control session. + * @return int + */ +int msi_reject ( MSISession* session ); + + +/** + * @brief Terminate the current call. + * + * @param session Control session. + * @return int + */ +int msi_stopcall ( MSISession* session ); + +#endif /* __TOXMSI */ diff --git a/toxav/toxrtp.c b/toxav/toxrtp.c new file mode 100755 index 00000000..2363deea --- /dev/null +++ b/toxav/toxrtp.c @@ -0,0 +1,878 @@ +/** toxrtp.c + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "toxrtp.h" +#include +#include +#include + +#include "../toxcore/util.h" +#include "../toxcore/network.h" +#include "../toxcore/net_crypto.h" +#include "../toxcore/Messenger.h" + +#define PAYLOAD_ID_VALUE_OPUS 1 +#define PAYLOAD_ID_VALUE_VP8 2 + +#define MAX_SEQU_NUM 65535 + +#define size_32 4 + +#define inline__ inline __attribute__((always_inline)) + + +#define ADD_FLAG_VERSION(_h, _v) do { ( _h->flags ) &= 0x3F; ( _h->flags ) |= ( ( ( _v ) << 6 ) & 0xC0 ); } while(0) +#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) +#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0) +#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0) +#define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0) +#define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0) + +#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6) +#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5) +#define GET_FLAG_EXTENSION(_h) (( _h->flags & 0x10 ) >> 4) +#define GET_FLAG_CSRCC(_h) ( _h->flags & 0x0f ) +#define GET_SETTING_MARKER(_h) (( _h->marker_payloadt ) >> 7) +#define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) + + + +/** + * @brief Checks if message came in late. + * + * @param session Control session. + * @param msg The message. + * @return int + * @retval -1 The message came in order. + * @retval 0 The message came late. + */ +inline__ int check_late_message (RTPSession* session, RTPMessage* msg) +{ + /* + * Check Sequence number. If this new msg has lesser number then the session->rsequnum + * it shows that the message came in late. Also check timestamp to be 100% certain. + * + */ + return ( msg->header->sequnum < session->rsequnum && msg->header->timestamp < session->timestamp ) ? 0 : -1; +} + + +/** + * @brief Increases nonce value by 'target' + * + * @param nonce The nonce + * @param target The target + * @return void + */ +inline__ void increase_nonce(uint8_t* nonce, uint16_t target) +{ + uint16_t _nonce_counter = ((uint16_t)( + (((uint16_t) nonce [crypto_box_NONCEBYTES - 1]) << 8 ) | + (((uint16_t) nonce [crypto_box_NONCEBYTES - 2]) ))); + + /* Check overflow */ + if (_nonce_counter > USHRT_MAX - target ) { /* 2 bytes are not long enough */ + int _it = 3; + while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ? crypto_box_NONCEBYTES : 1; + + _nonce_counter = _nonce_counter - (USHRT_MAX - target ); /* Assign the rest of it */ + } else { /* Increase nonce */ + + _nonce_counter+= target; + } + + /* Assign the 8 last bytes */ + + nonce [crypto_box_NONCEBYTES - 1] = (uint8_t) (_nonce_counter >> 8); + nonce [crypto_box_NONCEBYTES - 2] = (uint8_t) (_nonce_counter); +} + + +/** + * @brief Speaks for it self. + * + */ +static const uint32_t payload_table[] = +{ + 8000, 8000, 8000, 8000, 8000, 8000, 16000, 8000, 8000, 8000, /* 0-9 */ + 44100, 44100, 0, 0, 90000, 8000, 11025, 22050, 0, 0, /* 10-19 */ + 0, 0, 0, 0, 0, 90000, 90000, 0, 90000, 0, /* 20-29 */ + 0, 90000, 90000, 90000, 90000, 0, 0, 0, 0, 0, /* 30-39 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-49 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-59 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-69 */ + PAYLOAD_ID_VALUE_OPUS, PAYLOAD_ID_VALUE_VP8, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-79 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-89 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-99 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 100-109 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110-119 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 120-127 */ +}; + + +/** + * @brief Extracts header from payload. + * + * @param payload The payload. + * @param length The size of payload. + * @return RTPHeader* Extracted header. + * @retval NULL Error occurred while extracting header. + */ +RTPHeader* extract_header ( const uint8_t* payload, size_t length ) +{ + if ( !payload ) { + return NULL; + } + + const uint8_t* _it = payload; + + RTPHeader* _retu = calloc(sizeof(RTPHeader), 1); + assert(_retu); + + _retu->flags = *_it; ++_it; + + /* This indicates if the first 2 bytes are valid. + * Now it my happen that this is out of order but + * it cuts down chances of parsing some invalid value + */ + if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ){ + /* Deallocate */ + free(_retu); + return NULL; + } + + /* + * Added a check for the size of the header little sooner so + * I don't need to parse the other stuff if it's bad + */ + uint8_t _cc = GET_FLAG_CSRCC ( _retu ); + uint32_t _length = 12 /* Minimum header len */ + ( _cc * 4 ); + + if ( length < _length ) { + /* Deallocate */ + free(_retu); + return NULL; + } + + if ( _cc > 0 ) { + _retu->csrc = calloc ( sizeof ( uint32_t ), _cc ); + assert(_retu->csrc); + + } else { /* But this should not happen ever */ + /* Deallocate */ + free(_retu); + return NULL; + } + + + _retu->marker_payloadt = *_it; ++_it; + _retu->length = _length; + + _retu->timestamp = ( ( uint32_t ) * _it << 24 ) | + ( ( uint32_t ) * ( _it + 1 ) << 16 ) | + ( ( uint32_t ) * ( _it + 2 ) << 8 ) | + ( * ( _it + 3 ) ) ; + + _it += 4; + + _retu->ssrc = ( ( uint32_t ) * _it << 24 ) | + ( ( uint32_t ) * ( _it + 1 ) << 16 ) | + ( ( uint32_t ) * ( _it + 2 ) << 8 ) | + ( ( uint32_t ) * ( _it + 3 ) ) ; + + + size_t _x; + for ( _x = 0; _x < _cc; _x++ ) { + _it += 4; + _retu->csrc[_x] = ( ( uint32_t ) * _it << 24 ) | + ( ( uint32_t ) * ( _it + 1 ) << 16 ) | + ( ( uint32_t ) * ( _it + 2 ) << 8 ) | + ( ( uint32_t ) * ( _it + 3 ) ) ; + } + + return _retu; +} + +/** + * @brief Extracts external header from payload. Must be called AFTER extract_header()! + * + * @param payload The ITERATED payload. + * @param length The size of payload. + * @return RTPExtHeader* Extracted extension header. + * @retval NULL Error occurred while extracting extension header. + */ +RTPExtHeader* extract_ext_header ( const uint8_t* payload, size_t length ) +{ + const uint8_t* _it = payload; + + RTPExtHeader* _retu = calloc(sizeof(RTPExtHeader), 1); + assert(_retu); + + uint16_t _ext_length = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2; + + if ( length < ( _ext_length * sizeof(uint32_t) ) ) { + return NULL; + } + + _retu->length = _ext_length; + _retu->type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2; + + _retu->table = calloc(sizeof(uint32_t), _ext_length ); + assert(_retu->table); + + uint32_t* _table = _retu->table; + size_t _i; + for ( _i = 0; _i < _ext_length; _i++ ) { + _it += 4; + _table[_i] = ( ( uint32_t ) * _it << 24 ) | + ( ( uint32_t ) * ( _it + 1 ) << 16 ) | + ( ( uint32_t ) * ( _it + 2 ) << 8 ) | + ( ( uint32_t ) * ( _it + 3 ) ) ; + } + + return _retu; +} + +/** + * @brief Adds header to payload. Make sure _payload_ has enough space. + * + * @param header The header. + * @param payload The payload. + * @return uint8_t* Iterated position. + */ +uint8_t* add_header ( RTPHeader* header, uint8_t* payload ) +{ + uint8_t _cc = GET_FLAG_CSRCC ( header ); + + uint8_t* _it = payload; + + + /* Add sequence number first */ + *_it = ( header->sequnum >> 8 ); ++_it; + *_it = ( header->sequnum ); ++_it; + + *_it = header->flags; ++_it; + *_it = header->marker_payloadt; ++_it; + + + uint32_t _timestamp = header->timestamp; + *_it = ( _timestamp >> 24 ); ++_it; + *_it = ( _timestamp >> 16 ); ++_it; + *_it = ( _timestamp >> 8 ); ++_it; + *_it = ( _timestamp ); ++_it; + + uint32_t _ssrc = header->ssrc; + *_it = ( _ssrc >> 24 ); ++_it; + *_it = ( _ssrc >> 16 ); ++_it; + *_it = ( _ssrc >> 8 ); ++_it; + *_it = ( _ssrc ); + + uint32_t *_csrc = header->csrc; + size_t _x; + for ( _x = 0; _x < _cc; _x++ ) { + ++_it; + *_it = ( _csrc[_x] >> 24 ); ++_it; + *_it = ( _csrc[_x] >> 16 ); ++_it; + *_it = ( _csrc[_x] >> 8 ); ++_it; + *_it = ( _csrc[_x] ); + } + + return _it; +} + +/** + * @brief Adds extension header to payload. Make sure _payload_ has enough space. + * + * @param header The header. + * @param payload The payload. + * @return uint8_t* Iterated position. + */ +uint8_t* add_ext_header ( RTPExtHeader* header, uint8_t* payload ) +{ + uint8_t* _it = payload; + + *_it = ( header->length >> 8 ); _it++; + *_it = ( header->length ); _it++; + + *_it = ( header->type >> 8 ); ++_it; + *_it = ( header->type ); + + size_t x; + + uint32_t* _hd_ext = header->table; + for ( x = 0; x < header->length; x++ ) { + ++_it; + *_it = ( _hd_ext[x] >> 24 ); ++_it; + *_it = ( _hd_ext[x] >> 16 ); ++_it; + *_it = ( _hd_ext[x] >> 8 ); ++_it; + *_it = ( _hd_ext[x] ); + } + + return _it; +} + +/** + * @brief Builds header from control session values. + * + * @param session Control session. + * @return RTPHeader* Created header. + */ +RTPHeader* build_header ( RTPSession* session ) +{ + RTPHeader* _retu; + _retu = calloc ( sizeof * _retu, 1 ); + assert(_retu); + + ADD_FLAG_VERSION ( _retu, session->version ); + ADD_FLAG_PADDING ( _retu, session->padding ); + ADD_FLAG_EXTENSION ( _retu, session->extension ); + ADD_FLAG_CSRCC ( _retu, session->cc ); + ADD_SETTING_MARKER ( _retu, session->marker ); + ADD_SETTING_PAYLOAD ( _retu, session->payload_type ); + + _retu->sequnum = session->sequnum; + _retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */ + _retu->ssrc = session->ssrc; + + if ( session->cc > 0 ) { + _retu->csrc = calloc(sizeof(uint32_t), session->cc); + assert(_retu->csrc); + + int i; + + for ( i = 0; i < session->cc; i++ ) { + _retu->csrc[i] = session->csrc[i]; + } + } else { + _retu->csrc = NULL; + } + + _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); + + return _retu; +} + + +/** + * @brief Parses data into RTPMessage struct. Stores headers separately from the payload data + * and so the length variable is set accordingly. _sequnum_ argument is + * passed by the handle_packet() since it's parsed already. + * + * @param session Control session. + * @param sequnum Sequence number that's parsed from payload in handle_packet() + * @param data Payload data. + * @param length Payload size. + * @return RTPMessage* + * @retval NULL Error occurred. + */ +RTPMessage* msg_parse ( RTPSession* session, uint16_t sequnum, const uint8_t* data, uint32_t length ) +{ + assert( length != -1); + + RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); + assert(_retu); + + _retu->header = extract_header ( data, length ); /* It allocates memory and all */ + + if ( !_retu->header ){ + free(_retu); + return NULL; + } + _retu->header->sequnum = sequnum; + + _retu->length = length - _retu->header->length; + + uint16_t _from_pos = _retu->header->length - 2 /* Since sequ num is excluded */ ; + + + if ( GET_FLAG_EXTENSION ( _retu->header ) ) { + _retu->ext_header = extract_ext_header ( data + _from_pos, length ); + if ( _retu->ext_header ){ + _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); + _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); + } else { + free (_retu->ext_header); + free (_retu->header); + free (_retu); + return NULL; + } + } else { + _retu->ext_header = NULL; + } + + /* Get the payload */ + _retu->data = calloc ( sizeof ( uint8_t ), _retu->length ); + assert(_retu->data); + + memcpy ( _retu->data, data + _from_pos, length - _from_pos ); + + _retu->next = NULL; + + + if ( session && check_late_message ( session, _retu) < 0 ){ + session->rsequnum = _retu->header->sequnum; + session->timestamp = _retu->header->timestamp; + } + + return _retu; +} + +/** + * @brief Callback for networking core. + * + * @param object RTPSession object. + * @param ip_port Where the message comes from. + * @param data Message data. + * @param length Message length. + * @return int + * @retval -1 Error occurred. + * @retval 0 Success. + */ +int rtp_handle_packet ( void* object, IP_Port ip_port, uint8_t* data, uint32_t length ) +{ + RTPSession* _session = object; + RTPMessage* _msg; + + if ( !_session ) + return -1; + + uint8_t _plain[MAX_UDP_PACKET_SIZE]; + + uint16_t _sequnum = ( ( uint16_t ) data[1] << 8 ) | data[2]; + + /* Clculate the right nonce */ + uint8_t _calculated[crypto_box_NONCEBYTES]; + memcpy(_calculated, _session->decrypt_nonce, crypto_box_NONCEBYTES); + increase_nonce ( _calculated, _sequnum ); + + /* Decrypt message */ + int _decrypted_length = decrypt_data_symmetric( + (uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); + + /* This packet is either not encrypted properly or late + */ + if ( -1 == _decrypted_length ){ + + /* If this is the case, then the packet is most likely late. + * Try with old nonce cycle. + */ + if ( _session->rsequnum < _sequnum ) { + _decrypted_length = decrypt_data_symmetric( + (uint8_t*)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain ); + + if ( !_decrypted_length ) return -1; /* This packet is not encrypted properly */ + + /* Otherwise, if decryption is ok with new cycle, set new cycle + */ + } else { + increase_nonce ( _calculated, MAX_SEQU_NUM ); + _decrypted_length = decrypt_data_symmetric( + (uint8_t*)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); + + if ( !_decrypted_length ) return -1; /* This is just an error */ + + /* A new cycle setting. */ + memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_session->decrypt_nonce, _calculated, crypto_box_NONCEBYTES); + } + } + + _msg = msg_parse ( NULL, _sequnum, _plain, _decrypted_length ); + + if ( !_msg ) + return -1; + + /* Hopefully this goes well + * NOTE: Is this even used? + */ + memcpy(&_msg->from, &ip_port, sizeof(tox_IP_Port)); + + /* Check if message came in late */ + if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ + _session->rsequnum = _msg->header->sequnum; + _session->timestamp = _msg->header->timestamp; + } + + pthread_mutex_lock(&_session->mutex); + + if ( _session->last_msg ) { + _session->last_msg->next = _msg; + _session->last_msg = _msg; + } else { + _session->last_msg = _session->oldest_msg = _msg; + } + + pthread_mutex_unlock(&_session->mutex); + + return 0; +} + + + +/** + * @brief Stores headers and payload data in one container ( data ) + * and the length is set accordingly. Returned message is used for sending _only_. + * + * @param session The control session. + * @param data Payload data to send ( This is what you pass ). + * @param length Size of the payload data. + * @return RTPMessage* Created message. + * @retval NULL Error occurred. + */ +RTPMessage* rtp_new_message ( RTPSession* session, const uint8_t* data, uint32_t length ) +{ + if ( !session ) + return NULL; + + uint8_t* _from_pos; + RTPMessage* _retu = calloc(sizeof(RTPMessage), 1); + assert(_retu); + + /* Sets header values and copies the extension header in _retu */ + _retu->header = build_header ( session ); /* It allocates memory and all */ + _retu->ext_header = session->ext_header; + + + uint32_t _total_length = length + _retu->header->length; + + if ( _retu->ext_header ) { + _total_length += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); + /* Allocate Memory for _retu->_data */ + _retu->data = calloc ( sizeof _retu->data, _total_length ); + assert(_retu->data); + + _from_pos = add_header ( _retu->header, _retu->data ); + _from_pos = add_ext_header ( _retu->ext_header, _from_pos + 1 ); + } else { + /* Allocate Memory for _retu->_data */ + _retu->data = calloc ( sizeof _retu->data, _total_length ); + assert(_retu->data); + + _from_pos = add_header ( _retu->header, _retu->data ); + } + + /* + * Parses the extension header into the message + * Of course if any + */ + + /* Appends _data on to _retu->_data */ + memcpy ( _from_pos + 1, data, length ); + + _retu->length = _total_length; + + _retu->next = NULL; + + return _retu; +} + + +/******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + * + * + * + * PUBLIC API FUNCTIONS IMPLEMENTATIONS + * + * + * + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ******************************************************************************************************************** + ********************************************************************************************************************/ + + + + + + + + + +/** + * @brief Release all messages held by session. + * + * @param session The session. + * @return int + * @retval -1 Error occurred. + * @retval 0 Success. + */ +int rtp_release_session_recv ( RTPSession* session ) +{ + if ( !session ){ + return -1; + } + + RTPMessage* _tmp,* _it; + + pthread_mutex_lock(&session->mutex); + + for ( _it = session->oldest_msg; _it; _it = _tmp ){ + _tmp = _it->next; + rtp_free_msg( session, _it); + } + + session->last_msg = session->oldest_msg = NULL; + + pthread_mutex_unlock(&session->mutex); + + return 0; +} + + +/** + * @brief Get's oldes message in the list. + * + * @param session Where the list is. + * @return RTPMessage* The message. You _must_ call rtp_msg_free() to free it. + * @retval NULL No messages in the list, or no list. + */ +RTPMessage* rtp_recv_msg ( RTPSession* session ) +{ + if ( !session ) + return NULL; + + RTPMessage* _retu = session->oldest_msg; + + pthread_mutex_lock(&session->mutex); + + if ( _retu ) + session->oldest_msg = _retu->next; + + if ( !session->oldest_msg ) + session->last_msg = NULL; + + pthread_mutex_unlock(&session->mutex); + + return _retu; +} + + +/** + * @brief Sends data to _RTPSession::dest + * + * @param session The session. + * @param messenger Tox* object. + * @param data The payload. + * @param length Size of the payload. + * @return int + * @retval -1 On error. + * @retval 0 On success. + */ +int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ) +{ + RTPMessage* msg = rtp_new_message (session, data, length); + + if ( !msg ) return -1; + + uint8_t _send_data [ MAX_UDP_PACKET_SIZE ]; + + _send_data[0] = session->prefix; + + /* Generate the right nonce */ + uint8_t _calculated[crypto_box_NONCEBYTES]; + memcpy(_calculated, session->encrypt_nonce, crypto_box_NONCEBYTES); + increase_nonce ( _calculated, msg->header->sequnum ); + + /* Need to skip 2 bytes that are for sequnum */ + int encrypted_length = encrypt_data_symmetric( + (uint8_t*) session->encrypt_key, _calculated, msg->data + 2, msg->length - 2, _send_data + 3 ); + + int full_length = encrypted_length + 3; + + _send_data[1] = msg->data[0]; + _send_data[2] = msg->data[1]; + + + if ( full_length != sendpacket ( ((Messenger*)messenger)->net, *((IP_Port*) &session->dest), _send_data, full_length) ) { + printf("Rtp error: %s\n", strerror(errno)); + return -1; + } + + + /* Set sequ number */ + if ( session->sequnum >= MAX_SEQU_NUM ) { + session->sequnum = 0; + memcpy(session->encrypt_nonce, _calculated, crypto_box_NONCEBYTES); + } else { + session->sequnum++; + } + + rtp_free_msg ( session, msg ); + return 0; +} + + +/** + * @brief Speaks for it self. + * + * @param session The control session msg belongs to. It can be NULL. + * @param msg The message. + * @return void + */ +void rtp_free_msg ( RTPSession* session, RTPMessage* msg ) +{ + free ( msg->data ); + + if ( !session ){ + free ( msg->header->csrc ); + if ( msg->ext_header ){ + free ( msg->ext_header->table ); + free ( msg->ext_header ); + } + } else { + if ( session->csrc != msg->header->csrc ) + free ( msg->header->csrc ); + if ( msg->ext_header && session->ext_header != msg->ext_header ) { + free ( msg->ext_header->table ); + free ( msg->ext_header ); + } + } + + free ( msg->header ); + free ( msg ); +} + + +/** + * @brief Must be called before calling any other rtp function. It's used + * to initialize RTP control session. + * + * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType + * @param messenger Tox* object. + * @param friend_num Friend id. + * @param encrypt_key Speaks for it self. + * @param decrypt_key Speaks for it self. + * @param encrypt_nonce Speaks for it self. + * @param decrypt_nonce Speaks for it self. + * @return RTPSession* Created control session. + * @retval NULL Error occurred. + */ +RTPSession* rtp_init_session ( int payload_type, + Tox* messenger, + int friend_num, + const uint8_t* encrypt_key, + const uint8_t* decrypt_key, + const uint8_t* encrypt_nonce, + const uint8_t* decrypt_nonce +) +{ + Messenger* _messenger_casted = (Messenger*) messenger; + + IP_Port _dest = get_friend_ipport(_messenger_casted, friend_num ); + + /* This should be enough eh? */ + if ( _dest.port == 0) { + return NULL; + } + + RTPSession* _retu = calloc(sizeof(RTPSession), 1); + assert(_retu); + + networking_registerhandler(_messenger_casted->net, payload_type, rtp_handle_packet, _retu); + + _retu->version = RTP_VERSION; /* It's always 2 */ + _retu->padding = 0; /* If some additional data is needed about the packet */ + _retu->extension = 0; /* If extension to header is needed */ + _retu->cc = 1; /* Amount of contributors */ + _retu->csrc = NULL; /* Container */ + _retu->ssrc = randombytes_random(); + _retu->marker = 0; + _retu->payload_type = payload_table[payload_type]; + + _retu->dest = *((tox_IP_Port*)&_dest); + + _retu->rsequnum = _retu->sequnum = 1; + + _retu->ext_header = NULL; /* When needed allocate */ + _retu->framerate = -1; + _retu->resolution = -1; + + _retu->encrypt_key = encrypt_key; + _retu->decrypt_key = decrypt_key; + + /* Need to allocate new memory */ + _retu->encrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->encrypt_nonce); + _retu->decrypt_nonce = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->decrypt_nonce); + _retu->nonce_cycle = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); assert(_retu->nonce_cycle); + + memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES); + memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES); + + _retu->csrc = calloc(sizeof(uint32_t), 1); + assert(_retu->csrc); + + _retu->csrc[0] = _retu->ssrc; /* Set my ssrc to the list receive */ + + /* Also set payload type as prefix */ + _retu->prefix = payload_type; + + _retu->oldest_msg = _retu->last_msg = NULL; + + pthread_mutex_init(&_retu->mutex, NULL); + /* + * + */ + return _retu; +} + + +/** + * @brief Terminate the session. + * + * @param session The session. + * @param messenger The messenger who owns the session + * @return int + * @retval -1 Error occurred. + * @retval 0 Success. + */ +int rtp_terminate_session ( RTPSession* session, Tox* messenger ) +{ + if ( !session ) + return -1; + + networking_registerhandler(((Messenger*)messenger)->net, session->prefix, NULL, NULL); + + free ( session->ext_header ); + free ( session->csrc ); + free ( session->decrypt_nonce ); + free ( session->encrypt_nonce ); + free ( session->nonce_cycle ); + + pthread_mutex_destroy(&session->mutex); + + /* And finally free session */ + free ( session ); + + return 0; +} \ No newline at end of file diff --git a/toxav/toxrtp.h b/toxav/toxrtp.h new file mode 100755 index 00000000..b4275aba --- /dev/null +++ b/toxav/toxrtp.h @@ -0,0 +1,211 @@ +/** toxrtp.h + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + +#ifndef __TOXRTP +#define __TOXRTP + +#define RTP_VERSION 2 +#include +#include "../toxcore/tox.h" + +/** + * Standard rtp header + */ + +typedef struct _RTPHeader { + uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ + uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */ + uint16_t sequnum; /* Sequence Number */ + uint32_t timestamp; /* Timestamp */ + uint32_t ssrc; /* SSRC */ + uint32_t* csrc; /* CSRC's table */ + uint32_t length; /* Length of the header in payload string. */ + +} RTPHeader; + + +/** + * @brief Standard rtp extension header. + * + */ +typedef struct _RTPExtHeader { + uint16_t type; /* Extension profile */ + uint16_t length; /* Number of extensions */ + uint32_t* table; /* Extension's table */ + +} RTPExtHeader; + + +/** + * @brief Standard rtp message. + * + */ +typedef struct _RTPMessage { + RTPHeader* header; + RTPExtHeader* ext_header; + + uint8_t* data; + uint32_t length; + tox_IP_Port from; + + struct _RTPMessage* next; +} RTPMessage; + + +/** + * @brief Our main session descriptor. + * It measures the session variables and controls + * the entire session. There are functions for manipulating + * the session so tend to use those instead of directly modifying + * session parameters. + * + */ +typedef struct _RTPSession { + uint8_t version; + uint8_t padding; + uint8_t extension; + uint8_t cc; + uint8_t marker; + uint8_t payload_type; + uint16_t sequnum; /* Set when sending */ + uint16_t rsequnum; /* Check when recving msg */ + uint32_t timestamp; + uint32_t ssrc; + uint32_t* csrc; + + /* If some additional data must be sent via message + * apply it here. Only by allocating this member you will be + * automatically placing it within a message. + */ + RTPExtHeader* ext_header; + + /* External header identifiers */ + int resolution; + int framerate; + + + /* Since these are only references of the + * call structure don't allocate or free + */ + + const uint8_t* encrypt_key; + const uint8_t* decrypt_key; + uint8_t* encrypt_nonce; + uint8_t* decrypt_nonce; + + uint8_t* nonce_cycle; + + RTPMessage* oldest_msg; + RTPMessage* last_msg; /* tail */ + + /* Msg prefix for core to know when recving */ + uint8_t prefix; + + pthread_mutex_t mutex; + tox_IP_Port dest; + +} RTPSession; + + +/** + * @brief Release all messages held by session. + * + * @param session The session. + * @return int + * @retval -1 Error occurred. + * @retval 0 Success. + */ +int rtp_release_session_recv ( RTPSession* session ); + + +/** + * @brief Get's oldest message in the list. + * + * @param session Where the list is. + * @return RTPMessage* The message. You need to call rtp_msg_free() to free it. + * @retval NULL No messages in the list, or no list. + */ +RTPMessage* rtp_recv_msg ( RTPSession* session ); + + +/** + * @brief Sends msg to _RTPSession::dest + * + * @param session The session. + * @param msg The message + * @param messenger Tox* object. + * @return int + * @retval -1 On error. + * @retval 0 On success. + */ +int rtp_send_msg ( RTPSession* session, Tox* messenger, const uint8_t* data, uint16_t length ); + + +/** + * @brief Speaks for it self. + * + * @param session The control session msg belongs to. It can be NULL. + * @param msg The message. + * @return void + */ +void rtp_free_msg ( RTPSession* session, RTPMessage* msg ); + + +/** + * @brief Must be called before calling any other rtp function. It's used + * to initialize RTP control session. + * + * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType + * @param messenger Tox* object. + * @param friend_num Friend id. + * @param encrypt_key Speaks for it self. + * @param decrypt_key Speaks for it self. + * @param encrypt_nonce Speaks for it self. + * @param decrypt_nonce Speaks for it self. + * @return RTPSession* Created control session. + * @retval NULL Error occurred. + */ +RTPSession* rtp_init_session ( int payload_type, + Tox* messenger, + int friend_num, + const uint8_t* encrypt_key, + const uint8_t* decrypt_key, + const uint8_t* encrypt_nonce, + const uint8_t* decrypt_nonce ); + + +/** + * @brief Terminate the session. + * + * @param session The session. + * @param messenger The messenger who owns the session + * @return int + * @retval -1 Error occurred. + * @retval 0 Success. + */ +int rtp_terminate_session ( RTPSession* session, Tox* messenger ); + + + +#endif /* __TOXRTP */ diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 51b4c20b..6c4e297f 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -29,6 +29,8 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/group_chats.c \ ../toxcore/assoc.h \ ../toxcore/assoc.c \ + ../toxcore/event.h \ + ../toxcore/event.c \ ../toxcore/onion.h \ ../toxcore/onion.c \ ../toxcore/onion_announce.h \ diff --git a/toxcore/event.c b/toxcore/event.c new file mode 100755 index 00000000..17e68c87 --- /dev/null +++ b/toxcore/event.c @@ -0,0 +1,335 @@ +/** event.c + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include "event.h" + +#include "util.h" + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#define RUN_IN_THREAD(func, args) { pthread_t _tid; \ + pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); } + +#define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) +#define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex) + +#define FREQUENCY 10000 + +#define inline__ inline __attribute__((always_inline)) + + +typedef struct _EventContainer { + void* (*func)(void*); + void* func_args; + unsigned timeout; + long long id; + +} EventContainer; + +typedef struct _EventHandler { + EventContainer* timed_events; + size_t timed_events_count; + + int running; + + pthread_mutex_t mutex; + +} EventHandler; + +int throw_event( void* (func)(void*), void* arg ); +int reset_timer_event ( int id, uint32_t timeout ); +int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout); +int cancel_timer_event ( int id ); +int execute_timer_event ( int id ); + +struct _Event event = +{ + throw_event, + /* reset_timer_event */ NULL, + throw_timer_event, + cancel_timer_event, + /*execute_timer_event*/ NULL +}; + +/* + * Random functions used by this file + */ +void clear_events (EventContainer** event_container, size_t* counter) +{ + free(*event_container ); + + *event_container = NULL; + *counter = 0; +} + +int pop_id ( EventContainer** event_container, size_t* counter, int id ) +{ + if ( !*event_container || !*counter || !id ) + return -1; + + EventContainer* _it = *event_container; + int i; + + for ( i = *counter; i; -- i ){ + if ( _it->id == id ) { /* Hit! */ + break; + } + ++_it; + } + + if ( i ) { + for ( ; i; -- i ){ *_it = *(_it + 1); ++_it; } + -- (*counter ); + *event_container = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */ + + return 0; + + } + + /* not found here */ + + return -1; +} + +void push_event ( EventContainer** container, size_t* counter, void* (func)(void*), void* arg ) +{ + (*container ) = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1)); + assert((*container ) != NULL); + + (*container )[*counter].func = func; + (*container )[*counter].func_args = arg; + (*container )[*counter].timeout = 0; + (*container )[*counter].id = 0; + + (*counter )++; +} + +void reorder_events ( size_t counter, EventContainer* container, unsigned timeout ) +{ + if ( counter > 1 ) { + + int i = counter - 1; + + /* start from behind excluding last added member */ + EventContainer* _it = &container[i - 1]; + + EventContainer _last_added = container[i]; + + for ( ; i; --i ) { + if ( _it->timeout > timeout ){ + *(_it + 1) = *_it; + *_it = _last_added; -- _it; + } + } + + } +} + +/* ============================================= */ + +/* main poll for event execution */ +void* event_poll( void* arg ) +{ + EventHandler* _event_handler = arg; + + while ( _event_handler->running ) + { + + LOCK( _event_handler ); + + if ( _event_handler->timed_events ){ + + uint32_t _time = ((uint32_t)(current_time() / 1000)); + + if ( _event_handler->timed_events[0].timeout < _time ) { + + RUN_IN_THREAD ( _event_handler->timed_events[0].func, + _event_handler->timed_events[0].func_args ); + + pop_id(&_event_handler->timed_events, + &_event_handler->timed_events_count, + _event_handler->timed_events[0].id); + + } + + } + + UNLOCK( _event_handler ); + + usleep(FREQUENCY); + } + +LOCK( _event_handler ); + + clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count); + +UNLOCK( _event_handler ); + + _event_handler->running = -1; + pthread_exit(NULL); +} + +int throw_event( void* (func)(void*), void* arg ) +{ + pthread_t _tid; + int _rc = + pthread_create(&_tid, NULL, func, arg ); + + return (0 != _rc ) ? _rc : pthread_detach(_tid); +} + +EventHandler event_handler; + +/* Place and order array of timers */ +int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout) +{ + static int _unique_id = 1; + + push_event(&event_handler.timed_events, &(event_handler.timed_events_count), func, arg ); + + size_t _counter = event_handler.timed_events_count; + + event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000)); + event_handler.timed_events[_counter - 1].id = _unique_id; ++_unique_id; + + + /* reorder */ + + reorder_events(_counter, event_handler.timed_events, timeout ); + + return _unique_id - 1; +} + +int execute_timer_event ( int id ) +{ + int _status; + +LOCK((&event_handler)); + EventContainer* _it = event_handler.timed_events; + + int _i = event_handler.timed_events_count; + + /* Find it and execute */ + for ( ; _i; _i-- ) { + if ( _it->id == id ) { + RUN_IN_THREAD ( _it->func, _it->func_args ); + break; + } + ++_it; + } + + /* Now remove it from the queue */ + + if ( _i ) { + for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; } + -- event_handler.timed_events_count; + + event_handler.timed_events = realloc + (event_handler.timed_events, sizeof(EventContainer) * event_handler.timed_events_count); /* resize */ + + _status = 0; + + } + else _status = -1; + +UNLOCK((&event_handler)); + + return _status; +} + +int reset_timer_event ( int id, uint32_t timeout ) +{ + int _status; + +LOCK((&event_handler)); + + EventContainer* _it = event_handler.timed_events; + + int _i = event_handler.timed_events_count; + + /* Find it and change */ + for ( ; _i; _i-- ) { + if ( _it->id == id ) { + _it->timeout = timeout + ((uint32_t)(current_time() / 1000)); + break; + } + ++_it; + } + + _status = _i ? -1 : 0; + +UNLOCK((&event_handler)); + + return _status; +} + +/* Remove timer from array */ +inline__ int cancel_timer_event ( int id ) +{ + return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id ); +} + + +/* Initialization and termination of event polls + * This will be run at the beginning and the end of the program execution. + * I think that's the best way to do it. + */ + +void __attribute__((constructor)) init_event_poll () +{ + event_handler.timed_events = NULL; + event_handler.timed_events_count = 0; + + event_handler.running = 1; + + pthread_mutex_init(&event_handler.mutex, NULL); + + RUN_IN_THREAD(event_poll, &event_handler); +} + +void __attribute__((destructor)) terminate_event_poll() +{ + /* Exit thread */ + event_handler.running = 0; + + /* Keep the global until thread exits */ + while (event_handler.running > -1) { + event_handler.running; + usleep(FREQUENCY*2); + } + + pthread_mutex_destroy( &event_handler.mutex ); +} diff --git a/toxcore/event.h b/toxcore/event.h new file mode 100755 index 00000000..690cc1ca --- /dev/null +++ b/toxcore/event.h @@ -0,0 +1,51 @@ +/** event.h + * + * 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 . + * + * + * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or + * my email: eniz_vukovic@hotmail.com + */ + + +#ifndef __TOXEVENT +#define __TOXEVENT + + +/** + * - Events are, in fact, ran in their own threads upon execution. + * - Event handler is initialized at the start, before the main() function + * and terminated after it's execution. + * - Timers are checked for timeout every ~10000 ns. + * - Timers can be canceled or ran immediately via + * timer_release() or timer_now() functions. + * - Timeout is measured in milliseconds. + * + * NOTE: timer_reset () and timer_now() are not tested nor usable atm + * + */ +extern struct _Event +{ + int (*rise) (void* ( func ) ( void* ), void* arg); + int (*timer_reset ) ( int id, unsigned timeout ); + int (*timer_alloc) (void* ( func ) ( void* ), void* arg, unsigned timeout); + int (*timer_release) (int id); + int (*timer_now) ( int id ); +} event; + +#endif /* _MSI__EVENT_H_ */ diff --git a/toxmsi/Makefile.inc b/toxmsi/Makefile.inc deleted file mode 100644 index 7d620e70..00000000 --- a/toxmsi/Makefile.inc +++ /dev/null @@ -1,69 +0,0 @@ -if BUILD_AV - -lib_LTLIBRARIES += libtoxmsi.la - -libtoxmsi_la_include_HEADERS = \ - ../toxmsi/toxmsi.h \ - ../toxmsi/toxmedia.h - -libtoxmsi_la_includedir = $(includedir)/tox - - -libtoxmsi_la_SOURCES = ../toxmsi/toxmsi.h \ - ../toxmsi/toxmsi.c \ - ../toxmsi/toxmsi_message.h \ - ../toxmsi/toxmsi_message.c \ - ../toxmsi/toxmsi_header.h \ - ../toxmsi/toxmsi_header.c \ - ../toxmsi/toxmsi_event.h \ - ../toxmsi/toxmsi_event.c \ - ../toxrtp/tests/test_helper.h \ - ../toxrtp/tests/test_helper.c - -libtoxmsi_la_CFLAGS = -I../toxcore \ - -I../toxmsi \ - -I../toxrtp \ - $(NACL_CFLAGS) \ - $(PTHREAD_CFLAGS) - -libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \ - $(EXTRA_LT_LDFLAGS) \ - $(NACL_LDFLAGS) \ - $(PTHREAD_LIBS) - -libtoxmsi_la_LIBS = $(NACL_LIBS) - -noinst_PROGRAMS += phone - -phone_SOURCES = ../toxmsi/phone.c \ - ../toxmsi/toxmedia.c - -phone_CFLAGS = -I../toxcore \ - -I../toxrtp \ - $(AVFORMAT_CFLAGS) \ - $(AVCODEC_CFLAGS) \ - $(AVUTIL_CFLAGS) \ - $(AVDEVICE_CFLAGS) \ - $(SWSCALE_CFLAGS) \ - $(SDL_CFLAGS) \ - $(OPENAL_CFLAGS) \ - $(NACL_CFLAGS) \ - $(OPUS_CFLAGS) \ - $(PTHREAD_CFLAGS) - - -phone_LDADD = $(PTHREAD_LIBS) \ - libtoxrtp.la \ - libtoxmsi.la \ - $(NACL_LDFLAGS) \ - $(AVFORMAT_LIBS) \ - $(AVCODEC_LIBS) \ - $(AVUTIL_LIBS) \ - $(AVDEVICE_LIBS) \ - $(SWSCALE_LIBS) \ - $(SDL_LIBS) \ - $(OPENAL_LIBS) \ - $(NACL_LIBS) \ - $(OPUS_LIBS) - -endif diff --git a/toxmsi/phone.c b/toxmsi/phone.c deleted file mode 100644 index 432be94c..00000000 --- a/toxmsi/phone.c +++ /dev/null @@ -1,668 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#define _BSD_SOURCE -#define _GNU_SOURCE - -#define _CT_PHONE - -#ifdef _CT_PHONE -#include "phone.h" -#include -#include -#include -#include -#include -/* #include Can this be removed? */ -#include -#include "toxmedia.h" - - - -void INFO (const char *_format, ...) -{ - printf("\r[!] "); - va_list _arg; - va_start (_arg, _format); - vfprintf (stdout, _format, _arg); - va_end (_arg); - printf("\n\r >> "); - fflush(stdout); -} - -int rtp_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length ) -{ - phone_t *_phone = _object; - rtp_msg_t *_msg; - uint8_t _payload_id; - - if ( _phone->_msi->_call && _phone->_msi->_call->_state == call_active ) { - - _msg = rtp_msg_parse ( NULL, data + 1, length - 1 ); /* ignore marker byte */ - - if ( !_msg ) - return 0; - - _payload_id = rtp_header_get_setting_payload_type(_msg->_header); - - if ( _payload_id == _PAYLOAD_OPUS && _phone->_rtp_audio ) - rtp_store_msg(_phone->_rtp_audio, _msg); - else if ( _payload_id == _PAYLOAD_VP8 && _phone->_rtp_video ) - rtp_store_msg(_phone->_rtp_video, _msg); - else rtp_free_msg( NULL, _msg); - } - - return SUCCESS; -} -int msi_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length ) -{ - msi_session_t *_session = _object; - msi_msg_t *_msg; - - _msg = msi_parse_msg ( data + 1 ); /* ignore marker byte */ - - if ( _msg ) { - /* my current solution for "hole punching" */ - _session->_friend_id = ip_port; - } else { - return FAILURE; - } - - /* place message in a session */ - msi_store_msg(_session, _msg); - - return SUCCESS; -} - -void *phone_receivepacket ( void *_phone_p ) -{ - phone_t *_phone = _phone_p; - - - networking_registerhandler(_phone->_networking, MSI_PACKET, msi_handlepacket, _phone->_msi); - networking_registerhandler(_phone->_networking, RTP_PACKET, rtp_handlepacket, _phone); - - /* Now start main networking loop */ - while ( _phone->_networking ) { /* so not thread safe */ - networking_poll(_phone->_networking); - usleep(10000); - } - - pthread_exit ( NULL ); -} - -/* Media transport callback */ -typedef struct hmtc_args_s { - rtp_session_t **_rtp_audio; - rtp_session_t **_rtp_video; - call_type *_local_type_call; - call_state *_this_call; - void *_core_handler; -} hmtc_args_t; - -void *phone_handle_media_transport_poll ( void *_hmtc_args_p ) -{ - rtp_msg_t *_audio_msg, * _video_msg; - - hmtc_args_t *_hmtc_args = _hmtc_args_p; - - rtp_session_t *_rtp_audio = *_hmtc_args->_rtp_audio; - rtp_session_t *_rtp_video = *_hmtc_args->_rtp_video; - - call_type *_type = _hmtc_args->_local_type_call; - void *_core_handler = _hmtc_args->_core_handler; - - - call_state *_this_call = _hmtc_args->_this_call; - - while ( *_this_call == call_active ) { - - // THREADLOCK() - - _audio_msg = rtp_recv_msg ( _rtp_audio ); - _video_msg = rtp_recv_msg ( _rtp_video ); - - if ( _audio_msg ) { - /* Do whatever with msg */ - puts("audio"); - /* Do whatever with msg - puts(_audio_msg->_data);*/ - rtp_free_msg ( _rtp_audio, _audio_msg ); - } - - if ( _video_msg ) { - /* Do whatever with msg */ - puts("video"); - /* Do whatever with msg - puts(_video_msg->_data); */ - rtp_free_msg ( _rtp_video, _video_msg ); - _video_msg = NULL; - } - - /* -------------------- */ - - _audio_msg = rtp_msg_new ( _rtp_audio, (const uint8_t *)"audio\0", 6 ) ; - rtp_send_msg ( _rtp_audio, _audio_msg, _core_handler ); - _audio_msg = NULL; - - if ( *_type == type_video ) { /* if local call send video */ - _video_msg = rtp_msg_new ( _rtp_video, (const uint8_t *)"video\0", 6 ) ; - rtp_send_msg ( _rtp_video, _video_msg, _core_handler ); - _video_msg = NULL; - } - - //THREADUNLOCK() - - usleep ( 10000 ); - /* -------------------- */ - } - - //THREADLOCK() - - if ( _audio_msg ) { - rtp_free_msg(_rtp_audio, _audio_msg); - } - - if ( _video_msg ) { - rtp_free_msg(_rtp_video, _video_msg); - } - - rtp_release_session_recv(_rtp_video); - rtp_release_session_recv(_rtp_audio); - - rtp_terminate_session(_rtp_audio); - rtp_terminate_session(_rtp_video); - - *_hmtc_args->_rtp_audio = NULL; - *_hmtc_args->_rtp_video = NULL; - - free(_hmtc_args_p); - - //THREADUNLOCK() - - INFO("Media thread finished!"); - - pthread_exit ( NULL ); -} - -pthread_t phone_startmedia_loop ( phone_t *_phone ) -{ - if ( !_phone ) { - return 0; - } - - int _status; - - uint8_t _prefix = RTP_PACKET; - - pthread_t _rtp_tid; - int _rtp_thread_running = 1; - - _phone->_rtp_audio = rtp_init_session ( -1, 1 ); - rtp_set_prefix ( _phone->_rtp_audio, &_prefix, 1 ); - rtp_add_receiver ( _phone->_rtp_audio, &_phone->_msi->_friend_id ); - rtp_set_payload_type(_phone->_rtp_audio, _PAYLOAD_OPUS); - - _phone->_rtp_video = rtp_init_session ( -1, 1 ); - rtp_set_prefix ( _phone->_rtp_video, &_prefix, 1 ); - rtp_add_receiver ( _phone->_rtp_video, &_phone->_msi->_friend_id ); - rtp_set_payload_type(_phone->_rtp_video, _PAYLOAD_VP8); - - - - hmtc_args_t *rtp_targs = calloc(sizeof(hmtc_args_t), 1); - - - rtp_targs->_rtp_audio = &_phone->_rtp_audio; - rtp_targs->_rtp_video = &_phone->_rtp_video; - rtp_targs->_local_type_call = &_phone->_msi->_call->_type_local; - rtp_targs->_this_call = &_phone->_msi->_call->_state; - rtp_targs->_core_handler = _phone->_networking; - - codec_state *cs; - cs = _phone->cs; - //_status = pthread_create ( &_rtp_tid, NULL, phone_handle_media_transport_poll, rtp_targs ); - cs->_rtp_audio = _phone->_rtp_audio; - cs->_rtp_video = _phone->_rtp_video; - cs->_networking = _phone->_networking; - cs->socket = _phone->_tox_sock; - cs->quit = 0; - - printf("support: %d %d\n", cs->support_send_audio, cs->support_send_video); - - if (cs->support_send_audio && cs->support_send_video) /* quick fix */ - pthread_create(&_phone->cs->encode_audio_thread, NULL, encode_audio_thread, _phone->cs); - - if (cs->support_receive_audio) - pthread_create(&_phone->cs->decode_audio_thread, NULL, decode_audio_thread, _phone->cs); - - if (cs->support_send_video) - pthread_create(&_phone->cs->encode_video_thread, NULL, encode_video_thread, _phone->cs); - - if (cs->support_receive_video) - pthread_create(&_phone->cs->decode_video_thread, NULL, decode_video_thread, _phone->cs); - -// - return 1; - - - - -} - - -/* Some example callbacks */ - -MCBTYPE callback_recv_invite ( MCBARGS ) -{ - const char *_call_type; - - msi_session_t *_msi = _arg; - - /* Get the last one */ - call_type _type = _msi->_call->_type_peer[_msi->_call->_participants - 1]; - - switch ( _type ) { - case type_audio: - _call_type = "audio"; - break; - - case type_video: - _call_type = "video"; - break; - } - - INFO( "Incoming %s call!", _call_type ); - -} -MCBTYPE callback_recv_trying ( MCBARGS ) -{ - INFO ( "Trying..."); -} -MCBTYPE callback_recv_ringing ( MCBARGS ) -{ - INFO ( "Ringing!" ); -} -MCBTYPE callback_recv_starting ( MCBARGS ) -{ - msi_session_t *_session = _arg; - - if ( !phone_startmedia_loop(_session->_agent_handler) ) { - INFO("Starting call failed!"); - } else { - INFO ("Call started! ( press h to hangup )"); - } -} -MCBTYPE callback_recv_ending ( MCBARGS ) -{ - msi_session_t *_session = _arg; - phone_t *_phone = _session->_agent_handler; - _phone->cs->quit = 1; - - if (_phone->cs->encode_video_thread) - pthread_join(_phone->cs->encode_video_thread, NULL); - - if (_phone->cs->encode_audio_thread) - pthread_join(_phone->cs->encode_audio_thread, NULL); - - if (_phone->cs->decode_audio_thread) - pthread_join(_phone->cs->decode_audio_thread, NULL); - - if (_phone->cs->decode_video_thread) - pthread_join(_phone->cs->decode_video_thread, NULL); - - SDL_Quit(); - printf("all A/V threads successfully shut down\n"); - - INFO ( "Call ended!" ); -} - -MCBTYPE callback_recv_error ( MCBARGS ) -{ - msi_session_t *_session = _arg; - - INFO( "Error: %s", _session->_last_error_str ); -} - -MCBTYPE callback_call_started ( MCBARGS ) -{ - msi_session_t *_session = _arg; - - if ( !phone_startmedia_loop(_session->_agent_handler) ) { - INFO("Starting call failed!"); - } else { - INFO ("Call started! ( press h to hangup )"); - } - -} -MCBTYPE callback_call_canceled ( MCBARGS ) -{ - INFO ( "Call canceled!" ); -} -MCBTYPE callback_call_rejected ( MCBARGS ) -{ - INFO ( "Call rejected!\n" ); -} -MCBTYPE callback_call_ended ( MCBARGS ) -{ - - msi_session_t *_session = _arg; - phone_t *_phone = _session->_agent_handler; - _phone->cs->quit = 1; - - if (_phone->cs->encode_video_thread) - pthread_join(_phone->cs->encode_video_thread, NULL); - - if (_phone->cs->encode_audio_thread) - pthread_join(_phone->cs->encode_audio_thread, NULL); - - if (_phone->cs->decode_audio_thread) - pthread_join(_phone->cs->decode_audio_thread, NULL); - - if (_phone->cs->decode_video_thread) - pthread_join(_phone->cs->decode_video_thread, NULL); - - SDL_Quit(); - printf("all A/V threads successfully shut down\n"); - - INFO ( "Call ended!" ); -} - -MCBTYPE callback_requ_timeout ( MCBARGS ) -{ - INFO( "No answer! " ); -} - - -phone_t *initPhone(uint16_t _listen_port, uint16_t _send_port) -{ - phone_t *_retu = calloc(sizeof(phone_t), 1); - _retu->cs = av_calloc(sizeof(codec_state), 1); - - /* Initialize our mutex */ - pthread_mutex_init ( &_mutex, NULL ); - - IP_Port _local; - ip_init(&_local.ip, 0); - _local.ip.ip4.uint32 = htonl ( INADDR_ANY ); - - /* Bind local receive port to any address */ - _retu->_networking = new_networking ( _local.ip, _listen_port ); - - if ( !_retu->_networking ) { - fprintf ( stderr, "new_networking() failed!\n" ); - return NULL; - } - - _retu->_send_port = _send_port; - _retu->_recv_port = _listen_port; - - _retu->_tox_sock = _retu->_networking->sock; - - _retu->_rtp_audio = NULL; - _retu->_rtp_video = NULL; - - - /* Initialize msi */ - _retu->_msi = msi_init_session ( _retu->_networking, (const uint8_t *)_USERAGENT ); - - if ( !_retu->_msi ) { - fprintf ( stderr, "msi_init_session() failed\n" ); - return NULL; - } - - /* Initiate codecs */ - init_encoder(_retu->cs); - init_decoder(_retu->cs); - - _retu->_msi->_agent_handler = _retu; - /* Initiate callbacks */ - msi_register_callback_send ( sendpacket ); /* Using core's send */ - - msi_register_callback_call_started ( callback_call_started ); - msi_register_callback_call_canceled ( callback_call_canceled ); - msi_register_callback_call_rejected ( callback_call_rejected ); - msi_register_callback_call_ended ( callback_call_ended ); - - msi_register_callback_recv_invite ( callback_recv_invite ); - msi_register_callback_recv_ringing ( callback_recv_ringing ); - msi_register_callback_recv_starting ( callback_recv_starting ); - msi_register_callback_recv_ending ( callback_recv_ending ); - msi_register_callback_recv_error(callback_recv_error); - - msi_register_callback_requ_timeout ( callback_requ_timeout ); - /* ------------------ */ - - /* Now start msi main loop. It's a must! - * Define a frequency in ms; 10 ms is just fine - */ - msi_start_main_loop ( _retu->_msi, 10 ); - - return _retu; -} - -pthread_t phone_startmain_loop(phone_t *_phone) -{ - int _status; - /* Start receive thread */ - pthread_t _recv_thread, _phone_loop_thread; - _status = pthread_create ( &_recv_thread, NULL, phone_receivepacket, _phone ); - - if ( _status < 0 ) { - printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) ); - return 0; - } - - _status = pthread_detach ( _recv_thread ); - - if ( _status < 0 ) { - printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) ); - return 0; - } - - _status = pthread_create ( &_phone_loop_thread, NULL, phone_poll, _phone ); - - if ( _status < 0 ) { - printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) ); - return 0; - } - - _status = pthread_join ( _phone_loop_thread, NULL ); - - if ( _status < 0 ) { - printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) ); - return 0; - } - - return _phone_loop_thread; -} - -void *phone_poll ( void *_p_phone ) -{ - phone_t *_phone = _p_phone; - - int _status = SUCCESS; - - char _line[100]; - size_t _len; - - - char _dest[17]; /* For parsing destination ip */ - memset(_dest, '\0', 17); - - INFO("Welcome to tox_phone version: " _USERAGENT "\n" - "Usage: \n" - "c [a/v] (type) [0.0.0.0] (dest ip) (calls dest ip)\n" - "h (if call is active hang up)\n" - "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n" - "r (reject incoming call)\n" - "q (quit)\n" - "================================================================================" - ); - - while ( 1 ) { - fgets(_line, sizeof(_line), stdin); - int i; - - for (i = 0; i < 100; i++) { - if (_line[i] == '\n') { - _line[i] = '\0'; - } - } - - _len = strlen(_line); - - if ( !_len ) { - printf(" >> "); - fflush(stdout); - continue; - } - - if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) { - INFO("Invalid input!"); - continue; - } - - switch (_line[0]) { - - case 'c': { - if ( _phone->_msi->_call ) { - INFO("Already in a call"); - break; - } - - call_type _ctype; - - if ( _len < 11 ) { - INFO("Invalid input; usage: c a/v 0.0.0.0"); - break; - } else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */ - _ctype = type_audio; - } else { /* video */ - _ctype = type_video; - } - - strcpy(_dest, _line + 4 ); - _status = t_setipport(_dest, _phone->_send_port, &(_phone->_msi->_friend_id)); - - if ( _status < 0 ) { - INFO("Could not resolve address!"); - } else { - /* Set timeout */ - msi_invite ( _phone->_msi, _ctype, 30 * 1000 ); - INFO("Calling!"); - } - - t_memset((uint8_t *)_dest, '\0', 17); - - } - break; - - case 'h': { - if ( !_phone->_msi->_call ) { - break; - } - - msi_hangup(_phone->_msi); - - INFO("Hung up..."); - - } - break; - - case 'a': { - if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) { - break; - } - - if ( _len > 1 && _line[2] == 'v' ) - msi_answer(_phone->_msi, type_video); - else - msi_answer(_phone->_msi, type_audio); - - } - break; - - case 'r': { - if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) { - break; - } - - msi_reject(_phone->_msi); - - INFO("Call Rejected..."); - - } - break; - - case 'q': { - INFO("Quitting!"); - pthread_exit(NULL); - } - - default: { - INFO("Invalid command!"); - } - break; - - } - - usleep(1000); - } - - pthread_exit(NULL); -} - -int quitPhone(phone_t *_phone) -{ - if ( _phone->_msi->_call ) { - msi_hangup(_phone->_msi); /* Hangup the phone first */ - } - - msi_terminate_session(_phone->_msi); - pthread_mutex_destroy ( &_mutex ); - - printf("\r[i] Quit!\n"); - return SUCCESS; -} - -/* ---------------------- */ - -int print_help ( const char *_name ) -{ - printf ( "Usage: %s -m (mode) -r/s ( for setting the ports on test version )\n", _name ); - return FAILURE; -} - -int main ( int argc, char *argv [] ) -{ - arg_t *_args = parse_args ( argc, argv ); - - const char *_mode = find_arg_duble ( _args, "-m" ); - uint16_t _listen_port; - uint16_t _send_port; - - if ( !_mode ) - return print_help ( argv[0] ); - - if ( _mode[0] == 'r' ) { - _send_port = 31000; - _listen_port = 31001; - } else if ( _mode[0] == 's' ) { - _send_port = 31001; - _listen_port = 31000; - } else return print_help ( argv[0] ); - - phone_t *_phone = initPhone(_listen_port, _send_port); - - if ( _phone ) { - phone_startmain_loop(_phone); - - quitPhone(_phone); - } - - return SUCCESS; -} - -#endif /* _CT_PHONE */ diff --git a/toxmsi/phone.h b/toxmsi/phone.h deleted file mode 100644 index f96aac73..00000000 --- a/toxmsi/phone.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _PHONE_H_ -#define _PHONE_H_ - -#include "toxmsi.h" -#include "../toxrtp/toxrtp.h" -#include "toxmsi_message.h" -#include "../toxrtp/toxrtp_message.h" -#include "../toxrtp/tests/test_helper.h" -#include -#include -#include "toxmedia.h" - -/* Define client version */ -#define _USERAGENT "tox_phone-v.0.2.1" - -static pthread_mutex_t _mutex; - -#define THREADLOCK() \ -pthread_mutex_lock ( &_mutex ); - -#define THREADUNLOCK() \ -pthread_mutex_unlock ( &_mutex ); - -typedef struct phone_s { - msi_session_t* _msi; - - rtp_session_t* _rtp_audio; - rtp_session_t* _rtp_video; - - uint32_t _frame_rate; - - uint16_t _send_port, _recv_port; - - int _tox_sock; - - pthread_t _medialoop_id; - codec_state *cs; - - Networking_Core* _networking; -} phone_t; - -phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port); -int quitPhone(phone_t* _phone); - -/* My recv functions */ -int rtp_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length ); -int msi_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length ); - -/* This is basically representation of networking_poll of toxcore */ -void* phone_receivepacket ( void* _phone ); - -/* Phones main loop */ -void* phone_poll ( void* _phone ); - -pthread_t phone_startmain_loop(phone_t* _phone); -pthread_t phone_startmedia_loop ( phone_t* _phone ); - -/* Thread handlers */ -void* phone_handle_receive_callback ( void* _p ); -void* phone_handle_media_transport_poll ( void* _hmtc_args_p ); - -#endif /* _PHONE_H_ */ diff --git a/toxmsi/toxmsi.c b/toxmsi/toxmsi.c deleted file mode 100644 index 38af28fb..00000000 --- a/toxmsi/toxmsi.c +++ /dev/null @@ -1,835 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#define _BSD_SOURCE - -#include "toxmsi.h" -#include "toxmsi_event.h" -#include "toxmsi_message.h" -#include "../toxrtp/toxrtp_helper.h" -#include "../toxcore/network.h" - -#include -#include -#include - -#define same(x, y) strcmp((const char*) x, (const char*) y) == 0 - -typedef enum { - error_deadcall = 1, /* has call id but it's from old call */ - error_id_mismatch, /* non-existing call */ - - error_no_callid, /* not having call id */ - error_no_call, /* no call in session */ - - error_busy -} msi_error_t; /* Error codes */ - -static inline const uint8_t *stringify_error(msi_error_t _error_code) -{ - static const uint8_t* strings[] = - { - (uint8_t*)"", - (uint8_t*)"Using dead call", - (uint8_t*)"Call id not set to any call", - (uint8_t*)"Call id not available", - (uint8_t*)"No active call in session", - (uint8_t*)"Callee busy" - }; - - return strings[_error_code]; -} - -static inline const uint8_t *stringify_error_code(msi_error_t _error_code) -{ - static const uint8_t* strings[] = - { - (uint8_t*)"", - (uint8_t*)"1", - (uint8_t*)"2", - (uint8_t*)"3", - (uint8_t*)"4", - (uint8_t*)"5" - }; - - return strings[_error_code]; -} - -/* ******************* */ -/* --------- GLOBAL FUNCTIONS USED BY THIS FILE --------- */ - -/* CALLBACKS */ -/*int (*msi_send_message_callback) ( int, uint8_t*, uint32_t ) = NULL;*/ -int ( *msi_send_message_callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) = NULL; -int ( *msi_recv_message_callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) = NULL; - -MCBTYPE ( *msi_recv_invite_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_start_call_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_reject_call_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_cancel_call_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_end_call_callback ) ( MCBARGS ) = NULL; - -MCBTYPE ( *msi_ringing_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_starting_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_ending_callback ) ( MCBARGS ) = NULL; -MCBTYPE ( *msi_error_callback ) ( MCBARGS ) = NULL; - -MCBTYPE ( *msi_timeout_callback ) ( MCBARGS ) = NULL; -/* End of CALLBACKS */ - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -/* REGISTER CALLBACKS */ -/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) )*/ -void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) ) -{ - msi_send_message_callback = callback; -} - -void msi_register_callback_recv ( int ( *callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) ) -{ - msi_recv_message_callback = callback; -} - -/* Function to be called when received invite. - * This callback is all about what you do with it. - * Everything else is done internally. - */ -void msi_register_callback_recv_invite ( MCALLBACK ) -{ - msi_recv_invite_callback = callback; -} - -/* Function to be called when the call is started - * This callback is all about what you do with it. - * Everything else is done internally. - */ -void msi_register_callback_call_started ( MCALLBACK ) -{ - msi_start_call_callback = callback; -} - -/* Function to be called when call is rejected - * This callback is all about what you do with it. - * Everything else is done internally. - */ -void msi_register_callback_call_rejected ( MCALLBACK ) -{ - msi_reject_call_callback = callback; -} - -/* Function to be called when call is canceled - * This callback is all about what you do with it. - * Everything else is done internally. - */ -void msi_register_callback_call_canceled ( MCALLBACK ) -{ - msi_cancel_call_callback = callback; -} - -void msi_register_callback_call_ended ( MCALLBACK ) -{ - msi_end_call_callback = callback; -} - - -/* Functions to be called when gotten x response */ - -void msi_register_callback_recv_ringing ( MCALLBACK ) -{ - msi_ringing_callback = callback; -} -void msi_register_callback_recv_starting ( MCALLBACK ) -{ - msi_starting_callback = callback; -} -void msi_register_callback_recv_ending ( MCALLBACK ) -{ - msi_ending_callback = callback; -} - -void msi_register_callback_recv_error ( MCALLBACK ) -{ - msi_error_callback = callback; -} - -/* Timeout */ -void msi_register_callback_requ_timeout ( MCALLBACK ) -{ - msi_timeout_callback = callback; -} -/* END REGISTERING */ - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -/* Function for receiving and parsing a message that will be used internally */ - -msi_msg_t* receive_message ( msi_session_t* _session ) -{ - assert(_session); - - - msi_msg_t* _retu = _session->_oldest_msg; - - pthread_mutex_lock ( &_session->_mutex ); - - if ( _retu ) - _session->_oldest_msg = _retu->_next; - - if ( !_session->_oldest_msg ) - _session->_last_msg = NULL; - - pthread_mutex_unlock ( &_session->_mutex ); - - return _retu; -} - -void msi_store_msg ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - assert(_msg); - - pthread_mutex_lock ( &_session->_mutex ); - - if ( _session->_last_msg ) { - _session->_last_msg->_next = _msg; - _session->_last_msg = _msg; - } else { - _session->_last_msg = _session->_oldest_msg = _msg; - } - - pthread_mutex_unlock ( &_session->_mutex ); -} - -int msi_send_msg ( msi_session_t* _session, msi_msg_t* _msg ) -{ - int _status; - - if ( !_session->_call ) /* Which should never happen */ - return FAILURE; - - msi_msg_set_call_id ( _msg, _session->_call->_id ); - - uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; - t_memset ( _msg_string_final, '\0', MSI_MAXMSG_SIZE ); - - _msg_string_final[0] = 69; - - uint8_t* _msg_string = msi_msg_to_string ( _msg ); - - size_t _lenght = t_memlen ( _msg_string ); - - memcpy ( _msg_string_final + 1, _msg_string, _lenght ); - - _lenght += 1; - - _status = ( *msi_send_message_callback ) ( _session->_core_handler, _session->_friend_id, _msg_string_final, _lenght ); - - free ( _msg_string ); - - return _status; -} - -/* Random stuff */ -void flush_peer_type ( msi_session_t* _session, msi_msg_t* _msg, int _peer_id ) -{ - if ( _msg->_call_type ) { - if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) { - _session->_call->_type_peer[_peer_id] = type_audio; - - } else if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) { - _session->_call->_type_peer[_peer_id] = type_video; - } else {} /* Error */ - } else {} /* Error */ -} - -int has_call_error ( msi_session_t* _session, msi_msg_t* _msg ) -{ - msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) ); - - if ( !_msg->_call_id ) { - msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid) ); - - } else if ( !_session->_call ) { - msi_msg_set_reason(_msg_error, stringify_error_code(error_no_call) ); - - } else if ( strcmp((const char*)_session->_call->_id, (const char*)_msg->_call_id->_header_value ) != 0 ) { - msi_msg_set_reason(_msg_error, stringify_error_code(error_id_mismatch) ); - } - - if ( _msg_error->_reason ) { - msi_send_msg ( _session, _msg_error ); - msi_free_msg ( _msg_error ); - return SUCCESS; - } - - msi_free_msg ( _msg_error ); - return FAILURE; -} - -/* --------- END OF GLOBAL FUNCTIONS USED BY THIS FILE --------- */ - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent ) -{ - assert(_core_handler); - assert(_user_agent); - - msi_session_t* _session = calloc ( sizeof ( msi_session_t ), 1 ); - assert(_session); - - _session->_oldest_msg = _session->_last_msg = NULL; - _session->_core_handler = _core_handler; - - _session->_user_agent = t_strallcpy ( _user_agent ); - _session->_agent_handler = NULL; - - _session->_key = 0; - _session->_call = NULL; - - _session->_frequ = 10000; /* default value? */ - _session->_call_timeout = 30000; /* default value? */ - - /* Use the same frequency */ - _session->_event_handler = init_event_poll ( _session->_frequ ); - - pthread_mutex_init ( &_session->_mutex, NULL ); - - return _session; -} - -int msi_terminate_session ( msi_session_t* _session ) -{ - assert(_session); - - int _status = 0; - - terminate_event_poll ( _session->_event_handler ); - free ( _session ); - /* TODO: terminate the rest of the session */ - - pthread_mutex_destroy ( &_session->_mutex ); - - return _status; -} - -msi_call_t* msi_init_call ( msi_session_t* _session, int _peers, uint32_t _timeoutms ) -{ - assert(_session); - assert(_peers); - - msi_call_t* _call = calloc ( sizeof ( msi_call_t ), 1 ); - _call->_type_peer = calloc ( sizeof ( call_type ), _peers ); - - assert(_call); - assert(_call->_type_peer); - - _call->_participants = _peers; - _call->_key = _session->_key; - _call->_timeoutst = _timeoutms; - _call->_outgoing_timer_id = 0; - - return _call; -} - -int msi_terminate_call ( msi_session_t* _session ) -{ - assert(_session); - - if ( _session->_call->_type_peer ) - free ( _session->_call->_type_peer ); - - cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id); - - free ( _session->_call ); - - _session->_call = NULL; - - return SUCCESS; -} -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -/* STATE HANDLERS */ - -/* REQUESTS */ -int msi_handle_recv_invite ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( _session->_call ) { - msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) ); - msi_msg_set_reason(_msg_error, stringify_error_code(error_busy)); - msi_send_msg(_session, _msg_error); - msi_free_msg(_msg_error); - - return 0; - } - if ( !_msg->_call_id ) { - msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) ); - msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid)); - msi_send_msg(_session, _msg_error); - msi_free_msg(_msg_error); - return 0; - } - - _session->_call = msi_init_call ( _session, 1, _session->_call_timeout ); - t_memcpy(_session->_call->_id, _msg->_call_id->_header_value, _CALL_ID_LEN); - _session->_call->_state = call_starting; - - flush_peer_type ( _session, _msg, 0 ); - - msi_msg_t* _msg_ringing = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ringing ) ); - msi_send_msg ( _session, _msg_ringing ); - msi_free_msg ( _msg_ringing ); - - throw_event ( _session->_event_handler, msi_recv_invite_callback, _session ); - return 1; -} -int msi_handle_recv_start ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - _session->_call->_state = call_active; - - flush_peer_type ( _session, _msg, 0 ); - - throw_event ( _session->_event_handler, msi_start_call_callback, _session ); - return 1; -} -int msi_handle_recv_reject ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - msi_msg_t* _msg_end = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) ); - msi_send_msg ( _session, _msg_end ); - msi_free_msg ( _msg_end ); - - throw_event ( _session->_event_handler, msi_reject_call_callback, _session ); - - return 1; -} -int msi_handle_recv_cancel ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) ); - msi_send_msg ( _session, _msg_ending ); - msi_free_msg ( _msg_ending ); - - msi_terminate_call ( _session ); - - throw_event ( _session->_event_handler, msi_cancel_call_callback, _session ); - - return 1; -} -int msi_handle_recv_end ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) ); - msi_send_msg ( _session, _msg_ending ); - msi_free_msg ( _msg_ending ); - - msi_terminate_call ( _session ); - - throw_event ( _session->_event_handler, msi_end_call_callback, _session ); - - return 1; -} -/*--------*/ - -/* RESPONSES */ -int msi_handle_recv_ringing ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - throw_event ( _session->_event_handler, msi_ringing_callback, _session ); - - return 1; -} -int msi_handle_recv_starting ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - _session->_call->_state = call_active; - - msi_msg_t* _msg_start = msi_msg_new ( TYPE_REQUEST, stringify_request ( _start ) ); - msi_send_msg ( _session, _msg_start ); - msi_free_msg ( _msg_start ); - - flush_peer_type ( _session, _msg, 0 ); - - throw_event ( _session->_event_handler, msi_starting_callback, _session ); - cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id); - _session->_call->_outgoing_timer_id = 0; - - return 1; -} -int msi_handle_recv_ending ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - - if ( has_call_error(_session, _msg) == 0 ) - return 0; - - msi_terminate_call ( _session ); - throw_event ( _session->_event_handler, msi_ending_callback, _session ); - - return 1; -} -int msi_handle_recv_error ( msi_session_t* _session, msi_msg_t* _msg ) -{ - assert(_session); - assert(_session->_call); - - /* Handle error accordingly */ - if ( _msg->_reason ) { - _session->_last_error_id = atoi((const char*)_msg->_reason->_header_value); - _session->_last_error_str = stringify_error(_session->_last_error_id); - } - - msi_terminate_call(_session); - - throw_event ( _session->_event_handler, msi_error_callback, _session ); - - return 1; -} -/* ------------------ */ - -MCBTYPE msi_handle_timeout (void* _arg) -{ - msi_session_t* _session = _arg; - msi_terminate_call(_session); - - (*msi_timeout_callback) (_arg); - (*msi_ending_callback) (_arg); - -} - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms ) -{ - assert(_session); - - if ( !msi_send_message_callback ) - return 0; - - msi_msg_t* _msg_invite = msi_msg_new ( TYPE_REQUEST, stringify_request ( _invite ) ); - - _session->_call = msi_init_call ( _session, 1, _timeoutms ); /* Just one for now */ - msi_genterate_call_id(_session->_call->_id, _CALL_ID_LEN); - _session->_call->_type_local = _call_type; - /* Do whatever with message */ - - if ( _call_type == type_audio ) { - msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE ); - } else { - msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE ); - } - - msi_send_msg ( _session, _msg_invite ); - msi_free_msg ( _msg_invite ); - - _session->_call->_state = call_inviting; - - _session->_call->_outgoing_timer_id = throw_timer_event(_session->_event_handler, msi_handle_timeout, _session, _timeoutms ); - - return 1; -} -int msi_hangup ( msi_session_t* _session ) -{ - assert(_session); - - if ( !_session->_call || ( !msi_send_message_callback && _session->_call->_state != call_active ) ) - return 0; - - msi_msg_t* _msg_ending = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) ); - msi_send_msg ( _session, _msg_ending ); - msi_free_msg ( _msg_ending ); - - return 1; -} - - -int msi_answer ( msi_session_t* _session, call_type _call_type ) -{ - assert(_session); - - if ( !msi_send_message_callback || !_session->_call ) - return 0; - - msi_msg_t* _msg_starting = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _starting ) ); - _session->_call->_type_local = _call_type; - - if ( _call_type == type_audio ) { - msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE ); - } else { - msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE ); - } - - msi_send_msg ( _session, _msg_starting ); - msi_free_msg ( _msg_starting ); - - _session->_call->_state = call_active; - return 1; -} -int msi_cancel ( msi_session_t* _session ) -{ - assert(_session); - - if ( !_session->_call || !msi_send_message_callback ) - return 0; - - msi_msg_t* _msg_cancel = msi_msg_new ( TYPE_REQUEST, stringify_request ( _cancel ) ); - msi_send_msg ( _session, _msg_cancel ); - msi_free_msg ( _msg_cancel ); - - - - return 1; -} -int msi_reject ( msi_session_t* _session ) -{ - assert(_session); - - if ( !_session->_call || !msi_send_message_callback ) - return 0; - - msi_msg_t* _msg_reject = msi_msg_new ( TYPE_REQUEST, stringify_request ( _reject ) ); - msi_send_msg ( _session, _msg_reject ); - msi_free_msg ( _msg_reject ); - - return 1; -} - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -/* OUR MAIN POOL FUNCTION */ -/* - * Forks it self to other thread and then handles the session initiation. - * - * BASIC call flow: - * - * ALICE BOB - * | invite --> | - * | | - * | <-- ringing | - * | | - * | <-- starting | - * | | - * | start --> | - * | | - * | <-- MEDIA TRANS --> | - * | | - * | end --> | - * | | - * | <-- ending | - * - * Alice calls Bob by sending invite packet. - * Bob recvs the packet and sends an ringing packet; - * which notifies Alice that her invite is acknowledged. - * Ringing screen shown on both sides. - * Bob accepts the invite for a call by sending starting packet. - * Alice recvs the starting packet and sends the started packet to - * inform Bob that she recved the starting packet. - * Now the media transmission is established ( i.e. RTP transmission ). - * Alice hangs up and sends end packet. - * Bob recves the end packet and sends ending packet - * as the acknowledgement that the call is ending. - * - * - */ - - -/* - * Needs a bit more work on the protocol - */ -void* msi_poll_stack ( void* _session_p ) -{ - msi_session_t* _session = ( msi_session_t* ) _session_p; - msi_msg_t* _msg = NULL; - - uint32_t* _frequ = &_session->_frequ; - while ( _session ) { - - /* At this point it's already parsed */ - _msg = receive_message ( _session ); - - if ( _msg ) { - - if ( _msg->_request ) { /* Handle request */ - - const uint8_t* _request_value = _msg->_request->_header_value; - - if ( same ( _request_value, stringify_request ( _invite ) ) ) { - msi_handle_recv_invite ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( _start ) ) ) { - msi_handle_recv_start ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( _cancel ) ) ) { - msi_handle_recv_cancel ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( _reject ) ) ) { - msi_handle_recv_reject ( _session, _msg ); - - } else if ( same ( _request_value, stringify_request ( _end ) ) ) { - msi_handle_recv_end ( _session, _msg ); - } - - } else if ( _msg->_response ) { /* Handle response */ - - const uint8_t* _response_value = _msg->_response->_header_value; - - if ( same ( _response_value, stringify_response ( _ringing ) ) ) { - msi_handle_recv_ringing ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( _starting ) ) ) { - msi_handle_recv_starting ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( _ending ) ) ) { - msi_handle_recv_ending ( _session, _msg ); - - } else if ( same ( _response_value, stringify_response ( _error ) ) ) { - msi_handle_recv_error ( _session, _msg ); - } - - } - - msi_free_msg ( _msg ); - - } - usleep ( *_frequ ); - } - - return NULL; -} - -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ -/*------------------------*/ - -/* Easy way to start the poll */ - -pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms ) -{ - assert(_session); - - int _status; - pthread_t _thread_id; - - - _session->_frequ = _frequms * 1000; - - _status = pthread_create ( &_thread_id, NULL, msi_poll_stack, _session ); - - if ( _status < 0 ) { - printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) ); - return _status; - } - - _status = pthread_detach ( _thread_id ); - - if ( _status < 0 ) { - printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) ); - } - - return _thread_id; -} diff --git a/toxmsi/toxmsi.h b/toxmsi/toxmsi.h deleted file mode 100644 index d8985c64..00000000 --- a/toxmsi/toxmsi.h +++ /dev/null @@ -1,145 +0,0 @@ -/* msi_initiation.h -* -* Has function for session initiation along with session description. -* It follows the Tox API ( http://wiki.tox.im/index.php/Messaging_Protocol ). !Red! -* -* -* 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 _MSI_IMPL_H_ -#define _MSI_IMPL_H_ - -#include -#include "tox.h" -#include - -#define MCBTYPE void -#define MCBARGS void* _arg -#define MCALLBACK MCBTYPE(*callback)(void* _arg) - -#define MSI_PACKET 69 - -#define CT_AUDIO_HEADER_VALUE "AUDIO" -#define CT_VIDEO_HEADER_VALUE "VIDEO" - -/* define size for call_id */ -#define _CALL_ID_LEN 12 - -typedef enum { - type_audio = 1, - type_video, -} call_type; - -typedef enum { - call_inviting, /* when sending call invite */ - call_starting, /* when getting call invite */ - call_active, - call_hold - -} call_state; - -typedef int crypto_key; - -typedef struct msi_call_s { /* Call info structure */ - call_state _state; - call_type _type_local; - call_type* _type_peer; /* Support for conference starts with this */ - uint8_t _id[_CALL_ID_LEN]; /* Random value identifying the call */ - crypto_key _key; /* What is the type again? */ - uint16_t _participants; /* Number of participants */ - uint32_t _timeoutst; /* Time of the timeout for some action to end; 0 if infinite */ - int _outgoing_timer_id; /* Timer id */ - -} msi_call_t; - -typedef struct msi_session_s { - pthread_mutex_t _mutex; - - crypto_key _key; /* The key */ - - /* Call information/handler. ( Maybe only information? ) */ - msi_call_t* _call; - - /* Storage for message receiving */ - struct msi_msg_s* _oldest_msg; - struct msi_msg_s* _last_msg; /* tail */ - - /*int _friend_id;*/ - tox_IP_Port _friend_id; - - int _last_error_id; /* Determine the last error */ - const uint8_t* _last_error_str; - - const uint8_t* _user_agent; - - void* _agent_handler; /* Pointer to an object that is handling msi */ - void* _core_handler; /* Pointer to networking core or to anything that - * should handle interaction with core/networking - */ - void* _event_handler; /* Pointer to an object which handles the events */ - - uint32_t _frequ; - uint32_t _call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ -} msi_session_t; - - - -msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent ); -int msi_terminate_session ( msi_session_t* _session ); - -pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms ); - -/* Registering callbacks */ - -/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) );*/ -void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) ); - -/* Callbacks that handle the states */ -void msi_register_callback_call_started ( MCALLBACK ); -void msi_register_callback_call_canceled ( MCALLBACK ); -void msi_register_callback_call_rejected ( MCALLBACK ); -void msi_register_callback_call_ended ( MCALLBACK ); - -void msi_register_callback_recv_invite ( MCALLBACK ); -void msi_register_callback_recv_ringing ( MCALLBACK ); -void msi_register_callback_recv_starting ( MCALLBACK ); -void msi_register_callback_recv_ending ( MCALLBACK ); -void msi_register_callback_recv_error ( MCALLBACK ); - -void msi_register_callback_requ_timeout ( MCALLBACK ); -/* -------- */ - - -/* Function handling receiving from core */ -/*static int msi_handlepacket ( tox_IP_Port ip_port, uint8_t* _data, uint16_t _lenght ); */ - -/* functions describing the usage of msi */ -int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms ); -int msi_hangup ( msi_session_t* _session ); - -int msi_answer ( msi_session_t* _session, call_type _call_type ); -int msi_cancel ( msi_session_t* _session ); -int msi_reject ( msi_session_t* _session ); - -int msi_send_msg ( msi_session_t* _session, struct msi_msg_s* _msg ); -void msi_store_msg ( msi_session_t* _session, struct msi_msg_s* _msg ); - -#endif /* _MSI_IMPL_H_ */ diff --git a/toxmsi/toxmsi_event.c b/toxmsi/toxmsi_event.c deleted file mode 100644 index d8c0d269..00000000 --- a/toxmsi/toxmsi_event.c +++ /dev/null @@ -1,214 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include - -#include "toxmsi_event.h" - -#include "../toxrtp/toxrtp_helper.h" -#include -#include -#include - -static int _unique_id = 1; - -/* clear events */ -void clear_events (event_container_t** _event_container, size_t* _counter) -{ - assert( *_event_container ); - - free(*_event_container); - *_event_container = NULL; - - *_counter = 0; -} - -int pop_id ( event_container_t** _event_container, size_t* _counter, int _id ) -{ - if ( !*_event_container || !*_counter || !_id ) - return FAILURE; - - event_container_t* _it = *_event_container; - int i; - - for ( i = *_counter; i > 0 ; -- i ){ - if ( _it->_id == _id ) { /* Hit! */ - break; - } - ++_it; - } - - if ( i ) { - for ( ; i > 0; -- i ){ *_it = *(_it + 1); ++_it; } - -- (*_counter); - *_event_container = realloc(*_event_container, sizeof(event_container_t) * (*_counter)); /* resize */ - - if ( *_counter ) - assert(*_event_container); - - return SUCCESS; - - } else { - assert(i); - return FAILURE; - } -} - -/* main poll for event execution */ -void* event_poll( void* _event_handler_p ) -{ - event_handler_t* _event_handler = _event_handler_p; - uint32_t* _frequms = &_event_handler->_frequms; - - - while ( _event_handler->_running ) - { - - if ( _event_handler->_events_count ){ - pthread_mutex_lock(&_event_handler->_mutex); - - int i; - for ( i = 0; i < _event_handler->_events_count; i ++ ){ - _event_handler->_events[i]._event(_event_handler->_events[i]._event_args); - - } - clear_events(&_event_handler->_events, &_event_handler->_events_count); - - pthread_mutex_unlock(&_event_handler->_mutex); - } - - if ( _event_handler->_timed_events_count ){ - pthread_mutex_lock(&_event_handler->_mutex); - - uint32_t _time = t_time(); - - if ( _event_handler->_timed_events[0]._timeout < _time ) { - _event_handler->_timed_events[0]._event(_event_handler->_timed_events[0]._event_args); - - pop_id(&_event_handler->_timed_events, - &_event_handler->_timed_events_count, - _event_handler->_timed_events[0]._id); - } - pthread_mutex_unlock(&_event_handler->_mutex); - } - - - usleep(*_frequms); - } - - _event_handler->_running = -1; - pthread_exit(NULL); -} - -void push_event ( event_container_t** _container, size_t* _counter, event_t _func, event_arg_t _arg ) -{ - (*_counter)++; - (*_container) = realloc((*_container), sizeof(event_container_t) * (*_counter)); - assert((*_container) != NULL); - - (*_container[*_counter - 1])._event = _func; - (*_container[*_counter - 1])._event_args = _arg; - (*_container[*_counter - 1])._timeout = 0; - (*_container[*_counter - 1])._id = 0; -} - -void throw_event( void* _event_handler_p, event_t _func, event_arg_t _arg ) -{ - if ( !_func ) - return; - - event_handler_t* _event_handler = _event_handler_p; - - pthread_mutex_lock(&_event_handler->_mutex); - - push_event(&_event_handler->_events, &_event_handler->_events_count, _func, _arg); - - pthread_mutex_unlock(&_event_handler->_mutex); -} - -int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout) -{ - if ( !_func ) - return FAILURE; - - event_handler_t* _event_handler = _event_handler_p; - - pthread_mutex_lock(&_event_handler->_mutex); - - push_event(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _func, _arg); - size_t _counter = _event_handler->_timed_events_count; - _event_handler->_timed_events[_counter - 1]._timeout = _timeout + t_time(); - _event_handler->_timed_events[_counter - 1]._id = _unique_id; ++_unique_id; - - - /* reorder */ - if ( _counter > 1 ) { - - int i = _counter - 1; - /* start from behind excluding last added member */ - event_container_t* _it = &_event_handler->_timed_events[i - 1]; - - event_container_t _last_added = _event_handler->_timed_events[i]; - - for ( ; i > 0; --i ) { - if ( _it->_timeout > _timeout ){ - *(_it + 1) = *_it; - *_it = _last_added; -- _it; - } - } - - } - - pthread_mutex_unlock(&_event_handler->_mutex); - - return _event_handler->_timed_events[_counter - 1]._id; -} -int cancel_timer_event ( void* _event_handler_p, int _id ) -{ - event_handler_t* _event_handler = _event_handler_p; - return pop_id(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _id); -} - -event_handler_t* init_event_poll (uint32_t _frequms) -{ - event_handler_t* _retu = calloc(sizeof(event_handler_t), 1); - assert(_retu); - /* Initialize basic events */ - _retu->_events = NULL ; - - /* Initialize timed events */ - _retu->_timed_events = NULL; - - _retu->_frequms = _frequms; - _retu->_running = 1; - pthread_mutex_init(&_retu->_mutex, NULL); - - pthread_create(&_retu->_thread_id, NULL, event_poll, _retu); - int _rc = pthread_detach(_retu->_thread_id); - assert(_rc == 0); - - return _retu; -} - -int terminate_event_poll(event_handler_t* _handler) -{ - if ( !_handler ) - return FAILURE; - - _handler->_running = 0; - while (_handler->_running != -1); /* Wait for execution */ - - if (_handler->_events) - clear_events(&_handler->_events, &_handler->_events_count); - if (_handler->_events) - clear_events(&_handler->_timed_events, &_handler->_timed_events_count); - - pthread_mutex_destroy( &_handler->_mutex ); - - free(_handler); - - return SUCCESS; -} - diff --git a/toxmsi/toxmsi_event.h b/toxmsi/toxmsi_event.h deleted file mode 100644 index 032e4df5..00000000 --- a/toxmsi/toxmsi_event.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _MSI__EVENT_H_ -#define _MSI__EVENT_H_ - -#include -#include -#include - -typedef void* event_arg_t; - -typedef void ( *event_t ) ( event_arg_t ); -typedef void ( *timed_event_t ) ( event_arg_t ); - -typedef struct event_container_s { - event_t _event; - event_arg_t _event_args; - uint32_t _timeout; - long long _id; - -} event_container_t; - -typedef struct event_handler_s { - event_container_t* _events; - size_t _events_count; - - event_container_t* _timed_events; - size_t _timed_events_count; - - uint32_t _frequms; - int _running; - - pthread_mutex_t _mutex; - pthread_t _thread_id; - -} event_handler_t; - -event_handler_t* init_event_poll ( uint32_t _frequms ); -int terminate_event_poll ( event_handler_t* _event_handler ); - -void throw_event ( void* _event_handler_p, event_t _func, event_arg_t _arg ); - -/* Not yet ready for use */ -int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout); -int cancel_timer_event ( void* _event_handler_p, int _id ); - - -#endif /* _MSI__EVENT_H_ */ diff --git a/toxmsi/toxmsi_header.c b/toxmsi/toxmsi_header.c deleted file mode 100644 index 448ebc7f..00000000 --- a/toxmsi/toxmsi_header.c +++ /dev/null @@ -1,181 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "toxmsi_message.h" -#include -#include "../toxrtp/toxrtp_helper.h" -#include -#include "../toxcore/Lossless_UDP.h" - -#define ALLOC_ADD_DATA(_tempval, _hdrlist, _fielddef, _msgvar, _alloctype) \ -_tempval = msi_search_field(_hdrlist, (const uint8_t*)_fielddef); \ -if ( _tempval ){ \ - _msgvar = calloc(sizeof(_alloctype), 1); \ - assert(_msgvar); \ - _msgvar->_header_value = _tempval; \ -} - -uint8_t* msi_search_field ( msi_header_t* _list, const uint8_t* _field ) -{ - assert(_list); - assert(_field); - - msi_header_t* _iterator; - - for ( _iterator = _list; - _iterator && strcmp((const char*)_iterator->_header_field, (const char*)_field) != 0; - _iterator = _iterator->next ); - - if ( _iterator ){ - return t_strallcpy(_iterator->_header_value); - } else return NULL; -} - -int msi_parse_headers ( msi_msg_t* _msg ) -{ - assert(_msg); - - if ( !_msg->_headers ) - return FAILURE; - - msi_header_t* _list = _msg->_headers; - uint8_t* _field_current; - - ALLOC_ADD_DATA(_field_current, _list, _CALL_ID_FIELD, _msg->_call_id, msi_header_call_id_t) - ALLOC_ADD_DATA(_field_current, _list, _VERSION_FIELD, _msg->_version, msi_header_version_t) - ALLOC_ADD_DATA(_field_current, _list, _REQUEST_FIELD, _msg->_request, msi_header_request_t) - ALLOC_ADD_DATA(_field_current, _list, _RESPONSE_FIELD, _msg->_response, msi_header_response_t) - ALLOC_ADD_DATA(_field_current, _list, _FRIENDID_FIELD, _msg->_friend_id, msi_header_friendid_t) - ALLOC_ADD_DATA(_field_current, _list, _CALLTYPE_FIELD, _msg->_call_type, msi_header_call_type_t) - ALLOC_ADD_DATA(_field_current, _list, _USERAGENT_FIELD, _msg->_user_agent, msi_header_user_agent_t) - ALLOC_ADD_DATA(_field_current, _list, _INFO_FIELD, _msg->_info, msi_header_info_t) - ALLOC_ADD_DATA(_field_current, _list, _REASON_FIELD, _msg->_reason, msi_header_reason_t) - - /* Since we don't need the raw header anymore remove it */ - msi_header_t* _temp; - while ( _list ){ - _temp = _list->next; - free(_list->_header_field); - free(_list->_header_value); - free(_list); - _list = _temp; - } - - _msg->_headers = NULL; - - return SUCCESS; -} - -/* - * If you find better way of parsing values let me know - */ -msi_header_t* msi_add_new_header ( uint8_t* _value ) -{ - if ( !_value ) - return NULL; - - size_t _length = t_memlen(_value); - - if ( !_length ) { - return NULL; - } - - size_t _first_len = t_strfind(_value, (const uint8_t*)" "); - if ( !_first_len ){ - return NULL; - } - - size_t _second_len = (_length - _first_len); - if ( !_second_len ){ - return NULL; - } - - - uint8_t* _identifier = calloc(sizeof (uint8_t), (_first_len + 1) ); - uint8_t* _data = calloc(sizeof (uint8_t), (_second_len + 1) ); - - assert(_identifier); - assert(_data); - - - uint8_t* _p_it = _value; - size_t _num_it; - - for ( _num_it = 0; *_p_it != ' '; _num_it++ ){ - _identifier[_num_it] = *_p_it; - ++_p_it; - } - _identifier[_num_it] = '\0'; - ++_p_it; - - - for ( _num_it = 0; *_p_it != '\r'; _num_it++ ){ - _data[_num_it] = *_p_it; - ++_p_it; - } - _data[_num_it] = '\r'; - _data[_num_it + 1] = '\0'; - - msi_header_t* _retu = calloc(sizeof(msi_header_t), 1); - assert(_retu); - - _retu->_header_field = _identifier; - _retu->_header_value = _data; - - _retu->next = NULL; - - return _retu; -} - -msi_header_t* msi_parse_raw_data ( const uint8_t* _data ) -{ - assert(_data); - - uint8_t* _header_string; - - _header_string = (uint8_t*) strtok ((char*)_data, _RAW_TERMINATOR); - - msi_header_t* _head = msi_add_new_header(_header_string); - msi_header_t* _it = _head; - - while ( _header_string && _it ){ - - _header_string = (uint8_t*) strtok (NULL, _RAW_TERMINATOR); - _it->next = msi_add_new_header(_header_string); - if ( _it->next ){ - _it = _it->next; - } - } - - /* Iterate through list and remove all fault headers if any */ - - msi_header_t* _tmp = _it; - - for ( _it = _head; _it; _it = _it->next ){ - - if ( !_it->_header_value || !_it->_header_field ) { - _tmp ->next = _it->next; - - if ( _it->_header_field ) - free(_it->_header_field); - if ( _it->_header_value ) - free(_it->_header_value); - - if ( _it == _head ){ - _head = _head->next; - } - - free(_it); - _it = _tmp; - } else - _tmp = _it; - - } - - return _head; -} - - - diff --git a/toxmsi/toxmsi_header.h b/toxmsi/toxmsi_header.h deleted file mode 100644 index 599fafa3..00000000 --- a/toxmsi/toxmsi_header.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _MSI_HEADER_ -#define _MSI_HEADER_ - -/* Basic format of the unparsed header string - * ( No spaces in field allowed ) - * Version 0.1.1\n\r - * Request INVITE\n\r - * Response\n\r - * Friend-id ( from ip )\n\r - * Call-type AUDIO\n\r - * User-agent phone-v.1.0.0\n\r - */ - - -/* define raw header terminator */ -static const char* _RAW_TERMINATOR = "\n\r"; - -/* define string formats for the identifiers */ -#define _VERSION_FIELD "Version" -#define _REQUEST_FIELD "Request" -#define _RESPONSE_FIELD "Response" -#define _FRIENDID_FIELD "Friend-id" -#define _CALLTYPE_FIELD "Call-type" -#define _USERAGENT_FIELD "User-agent" -#define _INFO_FIELD "INFO" -#define _REASON_FIELD "Reason" -#define _CALL_ID_FIELD "Call-id" - -#define HEADER_VALUES \ -/*uint8_t* _header_field */ \ -uint8_t* _header_value; - -typedef struct msi_header_s { /* raw header list */ - uint8_t* _header_field; - uint8_t* _header_value; - - struct msi_header_s* next; - -} msi_header_t; - - - -typedef struct msi_header_version_s { /* Defines our version */ - HEADER_VALUES - -} msi_header_version_t; - -typedef struct msi_header_request_s { /* Defines our request */ - HEADER_VALUES - -} msi_header_request_t; - -typedef struct msi_header_response_s { /* Defines our response */ - HEADER_VALUES - -} msi_header_response_t; - -typedef struct msi_header_friendid_s { /* Defines source that sent the message */ - HEADER_VALUES - -} msi_header_friendid_t; - -typedef struct msi_header_call_type_s { /* Defines the type of the call */ - HEADER_VALUES - -} msi_header_call_type_t; - -typedef struct msi_header_user_agent_s { /* Defines the device of the participant */ - HEADER_VALUES - -} msi_header_user_agent_t; - - -typedef struct msi_header_call_id_s { /* Call id that is used to identify the call */ - HEADER_VALUES - -} msi_header_call_id_t; - -typedef struct msi_header_info_s { /* Defines informational message header */ - HEADER_VALUES - -} msi_header_info_t; - -typedef struct msi_header_reason_s { /* Defines reason mostly for error messages */ - HEADER_VALUES - -} msi_header_reason_t; - -struct msi_msg_s; - -/* - * Parses the header list to header types - */ -int msi_parse_headers ( struct msi_msg_s* _msg ); - -/* Make sure it's null terminated */ -msi_header_t* msi_parse_raw_data ( const uint8_t* _data ); - -#endif /* _MSI_HEADER_ */ diff --git a/toxmsi/toxmsi_message.c b/toxmsi/toxmsi_message.c deleted file mode 100644 index 72d7ee01..00000000 --- a/toxmsi/toxmsi_message.c +++ /dev/null @@ -1,267 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "toxmsi_message.h" -#include -#include -#include "../toxrtp/toxrtp_helper.h" -#include -#include - -#define ALLOCATE_HEADER(_header_type, _var, _m_header_value) \ -_var = calloc( sizeof(_header_type), 1 ); \ -assert(_var); \ -_var->_header_value = t_strallcpy((const uint8_t*)_m_header_value); - -#define DEALLOCATE_HEADER(_header) \ -if ( _header && _header->_header_value ) { \ -free( _header->_header_value ); \ -free( _header ); } - -#define SET_HEADER(_header_type, _var, _m_header_value) \ -if ( _var ){ \ -free(_var->_header_value); \ -free(_var);} \ -ALLOCATE_HEADER( _header_type, _var, _m_header_value ) - - -/* Sets empty message - */ -void set_msg ( msi_msg_t* _msg ) -{ - _msg->_call_type = NULL; - _msg->_version = NULL; - _msg->_request = NULL; - _msg->_response = NULL; - _msg->_friend_id = NULL; - _msg->_user_agent = NULL; - _msg->_call_id = NULL; - _msg->_reason = NULL; - _msg->_info = NULL; - _msg->_next = NULL; - _msg->_headers = NULL; -} - -void msi_free_msg ( msi_msg_t* _msg ) -{ - assert(_msg); - - DEALLOCATE_HEADER(_msg->_call_type); - DEALLOCATE_HEADER(_msg->_friend_id); - DEALLOCATE_HEADER(_msg->_request); - DEALLOCATE_HEADER(_msg->_response); - DEALLOCATE_HEADER(_msg->_user_agent); - DEALLOCATE_HEADER(_msg->_version); - DEALLOCATE_HEADER(_msg->_info); - DEALLOCATE_HEADER(_msg->_reason); - DEALLOCATE_HEADER(_msg->_call_id); - - free(_msg); -} - -void append_header_to_string ( uint8_t* _dest, const uint8_t* _header_field, const uint8_t* _header_value ) -{ - assert(_dest); - assert(_header_value); - assert(_header_field); - - size_t _dest_len = t_memlen(_dest); - - uint8_t* _storage_iterator = _dest + _dest_len; - const uint8_t* _header_fit = _header_field; - const uint8_t* _header_val = _header_value; - const uint8_t* _term_it = (const uint8_t*) _RAW_TERMINATOR; - - while ( *_header_fit ){ - *_storage_iterator = *_header_fit; - ++_header_fit; - ++_storage_iterator; - } - - *_storage_iterator = ' '; /* place space */ - ++_storage_iterator; - - while ( *_header_val ){ - *_storage_iterator = *_header_val; - ++_header_val; - ++_storage_iterator; - } - - while ( *_term_it ){ - *_storage_iterator = *_term_it; - ++_term_it; - ++_storage_iterator; - } -} - -msi_msg_t* msi_parse_msg ( const uint8_t* _data ) -{ - assert(_data); - - msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 ); - assert(_retu); - - set_msg(_retu); - - _retu->_headers = msi_parse_raw_data ( _data ); - - if ( msi_parse_headers (_retu) == FAILURE ) { - msi_free_msg(_retu); - return NULL; - } - - if ( !_retu->_version || strcmp((const char*)_retu->_version->_header_value, VERSION_STRING) != 0 ){ - msi_free_msg(_retu); - return NULL; - } - - return _retu; -} - - -uint8_t* msi_msg_to_string ( msi_msg_t* _msg ) -{ - assert(_msg); - - uint8_t* _retu = calloc(sizeof(uint8_t), MSI_MAXMSG_SIZE ); - assert(_retu); - - t_memset(_retu, '\0', MSI_MAXMSG_SIZE); - - if ( _msg->_version ){ - append_header_to_string(_retu, (const uint8_t*)_VERSION_FIELD, _msg->_version->_header_value); - } - - if ( _msg->_request ){ - append_header_to_string(_retu, (const uint8_t*)_REQUEST_FIELD, _msg->_request->_header_value); - } - - if ( _msg->_response ){ - append_header_to_string(_retu, (const uint8_t*)_RESPONSE_FIELD, _msg->_response->_header_value); - } - - if ( _msg->_friend_id ){ - append_header_to_string(_retu, (const uint8_t*)_FRIENDID_FIELD, _msg->_friend_id->_header_value); - } - - if ( _msg->_call_type ){ - append_header_to_string(_retu, (const uint8_t*)_CALLTYPE_FIELD, _msg->_call_type->_header_value); - } - - if ( _msg->_user_agent ){ - append_header_to_string(_retu, (const uint8_t*)_USERAGENT_FIELD, _msg->_user_agent->_header_value); - } - - if ( _msg->_info ){ - append_header_to_string(_retu, (const uint8_t*)_INFO_FIELD, _msg->_info->_header_value); - } - - if ( _msg->_call_id ){ - append_header_to_string(_retu, (const uint8_t*)_CALL_ID_FIELD, _msg->_call_id->_header_value); - } - - if ( _msg->_reason ){ - append_header_to_string(_retu, (const uint8_t*)_REASON_FIELD, _msg->_reason->_header_value); - } - - return _retu; -} - -msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _typeid ) -{ - msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 ); - assert(_retu); - - set_msg(_retu); - - if ( _type == TYPE_REQUEST ){ - ALLOCATE_HEADER( msi_header_request_t, _retu->_request, _typeid ) - _retu->_response = NULL; - - } else if ( _type == TYPE_RESPONSE ) { - ALLOCATE_HEADER( msi_header_response_t, _retu->_response, _typeid ) - _retu->_request = NULL; - - } else { - msi_free_msg(_retu); - return NULL; - } - - - ALLOCATE_HEADER( msi_header_version_t, _retu->_version, VERSION_STRING) - - _retu->_friend_id = NULL; - _retu->_call_type = NULL; - _retu->_user_agent = NULL; - _retu->_info = NULL; - - _retu->_next = NULL; - - return _retu; -} - -uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len ) -{ - assert(_storage); - - static const char _alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; /* avoids warning */ - - uint8_t _val = 0; - size_t _it; - - /* Generate random values 1-255 */ - for ( _it = 0; _it < _len; _it ++ ) { - while ( !_val ) _val = (uint8_t) _alphanum[ t_random(61) ]; - - _storage[_it] = _val; - _val = 0; - } - - return _storage; -} - -/* HEADER SETTING - */ - -void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ - assert(_msg); - assert(_header_field); - - SET_HEADER(msi_header_call_type_t, _msg->_call_type, _header_field) -} -void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ - assert(_msg); - assert(_header_field); - - SET_HEADER(msi_header_user_agent_t, _msg->_user_agent, _header_field) -} -void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ - assert(_msg); - assert(_header_field); - - SET_HEADER(msi_header_friendid_t, _msg->_friend_id, _header_field) -} -void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ -} -void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ - assert(_msg); - assert(_header_field); - - SET_HEADER(msi_header_reason_t, _msg->_reason, _header_field) -} -void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field ) -{ - assert(_msg); - assert(_header_field); - - SET_HEADER(msi_header_call_id_t, _msg->_call_id, _header_field) -} diff --git a/toxmsi/toxmsi_message.h b/toxmsi/toxmsi_message.h deleted file mode 100644 index 87dfccc2..00000000 --- a/toxmsi/toxmsi_message.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _MSI_MESSAGE_H_ -#define _MSI_MESSAGE_H_ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include -#include "../toxcore/network.h" -#include "../toxcore/tox.h" - -#include "toxmsi_header.h" - -#define TYPE_REQUEST 1 -#define TYPE_RESPONSE 2 - -#define VERSION_STRING "0.2.2" - -#define MSI_MAXMSG_SIZE 65535 - -typedef enum { - _invite, - _start, - _cancel, - _reject, - _end, - -} msi_request_t; - -static inline const uint8_t *stringify_request(msi_request_t _request) -{ - static const uint8_t* strings[] = - { - (uint8_t*)"INVITE", - (uint8_t*)"START", - (uint8_t*)"CANCEL", - (uint8_t*)"REJECT", - (uint8_t*)"END" - }; - - return strings[_request]; -} - -typedef enum { - _trying, - _ringing, - _starting, - _ending, - _error - -} msi_response_t; - -static inline const uint8_t *stringify_response(msi_response_t _response) -{ - static const uint8_t* strings[] = - { - (uint8_t*)"trying", - (uint8_t*)"ringing", - (uint8_t*)"starting", - (uint8_t*)"ending", - (uint8_t*)"error" - }; - - return strings[_response]; -} - - -typedef struct msi_msg_s { - /* This is the header list which contains unparsed headers */ - msi_header_t* _headers; - - /* Headers parsed */ - msi_header_version_t* _version; - msi_header_request_t* _request; - msi_header_response_t* _response; - msi_header_friendid_t* _friend_id; - msi_header_call_type_t* _call_type; - msi_header_user_agent_t* _user_agent; - msi_header_info_t* _info; - msi_header_reason_t* _reason; - msi_header_call_id_t* _call_id; - - /* Pointer to next member since it's list duuh */ - struct msi_msg_s* _next; - -} msi_msg_t; - - -/* - * Parse data received from socket - */ -msi_msg_t* msi_parse_msg ( const uint8_t* _data ); - -/* - * Make new message. Arguments: _type: (request, response); _type_field ( value ) - */ -msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _type_field ); - -/* Header setting */ -void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field ); -void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field ); -void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field ); -void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field ); -void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field ); -void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field ); - - -uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len ); -/* - * Parses message struct to string. - * Allocates memory so don't forget to free it - */ -uint8_t* msi_msg_to_string ( msi_msg_t* _msg ); - -/* - * msi_msg_s struct deallocator - */ -void msi_free_msg ( msi_msg_t* _msg ); - -#endif /* _MSI_MESSAGE_H_ */ diff --git a/toxrtp/Makefile.inc b/toxrtp/Makefile.inc deleted file mode 100644 index 801a7fd3..00000000 --- a/toxrtp/Makefile.inc +++ /dev/null @@ -1,34 +0,0 @@ -if BUILD_AV - -lib_LTLIBRARIES += libtoxrtp.la - -libtoxrtp_la_include_HEADERS = \ - ../toxrtp/toxrtp.h - -libtoxrtp_la_includedir = $(includedir)/tox - -libtoxrtp_la_SOURCES = ../toxrtp/toxrtp_error.h \ - ../toxrtp/toxrtp_error.c \ - ../toxrtp/toxrtp_error_id.h \ - ../toxrtp/toxrtp_helper.h \ - ../toxrtp/toxrtp_helper.c \ - ../toxrtp/toxrtp.h \ - ../toxrtp/toxrtp.c \ - ../toxrtp/toxrtp_message.h \ - ../toxrtp/toxrtp_message.c \ - ../toxcore/network.h \ - ../toxcore/network.c \ - ../toxcore/util.h \ - ../toxcore/util.c - -libtoxrtp_la_CFLAGS = -I../toxcore \ - -I../toxrtp \ - $(NACL_CFLAGS) - -libtoxrtp_la_LDFLAGS = $(TOXRTP_LT_LDFLAGS) \ - $(NACL_LDFLAGS) \ - $(EXTRA_LT_LDFLAGS) - -libtoxrtp_la_LIBS = $(NACL_LIBS) - -endif diff --git a/toxrtp/tests/Makefile.inc b/toxrtp/tests/Makefile.inc deleted file mode 100644 index 8d1c8b69..00000000 --- a/toxrtp/tests/Makefile.inc +++ /dev/null @@ -1 +0,0 @@ - diff --git a/toxrtp/tests/test_bidirect.c b/toxrtp/tests/test_bidirect.c deleted file mode 100644 index b5a0899e..00000000 --- a/toxrtp/tests/test_bidirect.c +++ /dev/null @@ -1,109 +0,0 @@ -#define _BSD_SOURCE - -#include "../toxrtp.h" -#include "../toxrtp_message.h" -#include -#include -#include -#include -#include - -#include "test_helper.h" -#include "../../toxcore/tox.h" - -#ifdef _CT_BIDIRECT - -int _print_help( const char* name ) -{ - char* _help = malloc( 300 ); - memset(_help, '\0', 300); - - strcat(_help, " Usage: "); - strcat(_help, name); - strcat(_help, "\n -d IP ( destination )\n" - " -p PORT ( dest Port )\n" - " -l PORT ( listen Port ) \n"); - - puts ( _help ); - - free(_help); - return FAILURE; -} - -int main( int argc, char* argv[] ) -{ - int status; - tox_IP_Port Ip_port; - const char* ip, *psend, *plisten; - uint16_t port_send, port_listen; - const uint8_t* test_bytes = "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789"; - - - rtp_session_t* _m_session; - rtp_msg_t *_m_msg_R, *_m_msg_S; - arg_t* _list = parse_args ( argc, argv ); - - ip = find_arg_duble(_list, "-d"); - psend = find_arg_duble(_list, "-p"); - plisten = find_arg_duble(_list, "-l"); - - if ( !ip || !plisten || !psend ) - return _print_help(argv[0]); - - port_send = atoi(psend); - port_listen = atoi(plisten); - - IP_Port local, remote; - - /* - * This is the Local ip. We initiate networking on - * this value for it's the local one. To make stuff simpler we receive over this value - * and send on the other one ( see remote ) - */ - local.ip.i = htonl(INADDR_ANY); - local.port = port_listen; - Networking_Core* _networking = new_networking(local.ip, port_listen); - - if ( !_networking ) - return FAILURE; - - int _socket = _networking->sock; - /* - * Now this is the remote. It's used by rtp_session_t to determine the receivers ip etc. - */ - t_setipport ( ip, port_send, &remote ); - _m_session = rtp_init_session(-1, -1); - rtp_add_receiver( _m_session, &remote ); - - /* Now let's start our main loop in both recv and send mode */ - - for ( ;; ) - { - /* - * This part checks for received messages and if gotten one - * display 'Received msg!' indicator and free message - */ - _m_msg_R = rtp_recv_msg ( _m_session ); - - if ( _m_msg_R ) { - puts ( "Received msg!" ); - rtp_free_msg(_m_session, _m_msg_R); - } - /* -------------------- */ - - /* - * This one makes a test msg and sends that message to the 'remote' - */ - _m_msg_S = rtp_msg_new ( _m_session, test_bytes, 280 ) ; - rtp_send_msg ( _m_session, _m_msg_S, _socket ); - usleep ( 10000 ); - /* -------------------- */ - } - - return SUCCESS; -} - -#endif /* _CT_BIDIRECT */ diff --git a/toxrtp/tests/test_headers.c b/toxrtp/tests/test_headers.c deleted file mode 100644 index be3f1375..00000000 --- a/toxrtp/tests/test_headers.c +++ /dev/null @@ -1,316 +0,0 @@ -/* test_headers.c - * - * Tests header parsing. You probably won't need this. !Red! - * - * - * 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 . - * - */ - -#include "test_helper.h" -#include "../toxrtp.h" -#include "../toxrtp_message.h" - -#include -#include -#include -#include -#include -#include "../toxrtp_error_id.h" - -#define _CT_HEADERS_ - -#ifdef _CT_HEADERS - -int _socket; -pthread_mutex_t _mutex; - -int print_help() -{ - puts ( - " Usage: Tuxrtp [-s (send mode) -d IP ( destination ) -p PORT ( dest Port )] \n" - " [-r ( recv mode ) ]" - ); - return FAILURE; -} - -void print_session_stats ( rtp_session_t* _m_session ) -{ - printf - ( - "Session test:\n" - "\tPackets sent:%d\n" - "\tPackets recv:%d\n\n" - "\tBytes sent:%d\n" - "\tBytes recv:%d\n\n" - "\tHeader CCSRs:%d\n" - , - _m_session->_packets_sent, - _m_session->_packets_recv, - _m_session->_bytes_sent, - _m_session->_bytes_recv, - _m_session->_cc - ); - - uint8_t i; - for ( i = 0; i < _m_session->_cc; i++ ) { - printf ( - "\t%d > :%d\n", i, _m_session->_csrc[i] - ); - } -} - -void print_header_info ( rtp_header_t* _header ) -{ - printf - ( - "Header info:\n" - "\tVersion :%d\n" - "\tPadding :%d\n" - "\tExtension :%d\n" - "\tCSRC count :%d\n" - "\tPayload type :%d\n" - "\tMarker :%d\n\n" - - "\tSSrc :%d\n" - "\tSequence num :%d\n" - "\tLenght: :%d\n" - "\tCSRC's:\n" - , - rtp_header_get_flag_version ( _header ), - rtp_header_get_flag_padding ( _header ), - rtp_header_get_flag_extension ( _header ), - rtp_header_get_flag_CSRC_count ( _header ), - rtp_header_get_setting_payload_type ( _header ), - rtp_header_get_setting_marker ( _header ), - - _header->_ssrc, - _header->_sequence_number, - _header->_length - ); - - - uint8_t i; - for ( i = 0; i < rtp_header_get_flag_CSRC_count ( _header ); i++ ) { - printf ( - "\t%d > :%d\n", i, _header->_csrc[i] - ); - } - - puts ( "\n" ); -} - -void print_ext_header_info(rtp_ext_header_t* _ext_header) -{ - printf - ( - "External Header info: \n" - "\tLenght :%d\n" - "\tID :%d\n" - "\tValue H :%d\n" - "\tValue W :%d\n\n", - _ext_header->_ext_len, - _ext_header->_ext_type, - rtp_get_resolution_marking_height(_ext_header, 0), - rtp_get_resolution_marking_width(_ext_header, 0) - ); -} - -int rtp_handlepacket ( rtp_session_t* _session, rtp_msg_t* _msg ) -{ - if ( !_msg ) - return FAILURE; - - if ( rtp_check_late_message(_session, _msg) < 0 ) { - rtp_register_msg(_session, _msg); - } - - if ( _session->_last_msg ) { - _session->_last_msg->_next = _msg; - _session->_last_msg = _msg; - } else { - _session->_last_msg = _session->_oldest_msg = _msg; - } - - - return SUCCESS; -} - -void* receivepacket_callback(void* _p_session) -{ - rtp_msg_t* _msg; - rtp_session_t* _session = _p_session; - - uint32_t _bytes; - tox_IP_Port _from; - uint8_t _socket_data[MAX_UDP_PACKET_SIZE]; - - int _m_socket = _socket; - - while ( 1 ) - { - int _status = receivepacket ( _m_socket, &_from, _socket_data, &_bytes ); - - if ( _status == FAILURE ) { /* nothing recved */ - usleep(1000); - continue; - } - - pthread_mutex_lock ( &_mutex ); - - _msg = rtp_msg_parse ( NULL, _socket_data, _bytes ); - rtp_handlepacket(_session, _msg); - - pthread_mutex_unlock ( &_mutex ); - } - - pthread_exit(NULL); -} - -int main ( int argc, char* argv[] ) -{ - arg_t* _list = parse_args ( argc, argv ); - - if ( _list == NULL ) { /* failed */ - return print_help(); - } - - pthread_mutex_init ( &_mutex, NULL ); - - int status; - IP_Port Ip_port; - const char* ip; - uint16_t port; - - - const uint8_t* test_bytes [300]; - memset(test_bytes, 'a', 300); - - rtp_session_t* _m_session; - rtp_msg_t* _m_msg; - - if ( find_arg_simple ( _list, "-r" ) != FAILURE ) { /* Server mode */ - - IP_Port LOCAL_IP; /* since you need at least 1 recv-er */ - LOCAL_IP.ip.i = htonl(INADDR_ANY); - LOCAL_IP.port = RTP_PORT; - LOCAL_IP.padding = -1; - - _m_session = rtp_init_session ( -1, -1 ); - Networking_Core* _networking = new_networking(LOCAL_IP.ip, RTP_PORT_LISTEN); - _socket = _networking->sock; - - - if ( !_networking ){ - pthread_mutex_destroy ( &_mutex ); - return FAILURE; - } - - int _socket = _networking->sock; - - if ( status < 0 ) { - pthread_mutex_destroy ( &_mutex ); - return FAILURE; - } - /* -- start in recv mode, get 1 message and then analyze it -- */ - pthread_t _tid; - RUN_IN_THREAD(receivepacket_callback, _tid, _m_session) - - for ( ; ; ) { /* Recv for x seconds */ - _m_msg = rtp_recv_msg ( _m_session ); - - /* _m_msg = rtp_session_get_message_queded ( _m_session ); DEPRECATED */ - if ( _m_msg ) { - /*rtp_free_msg(_m_session, _m_msg); - _m_msg = NULL;*/ - printf("Timestamp: %d\n", _m_msg->_header->_timestamp); - } - - usleep ( 10000 ); - } - - if ( _m_msg->_header ) { - rtp_header_print ( _m_msg->_header ); - } - if ( _m_msg->_ext_header ){ - print_ext_header_info(_m_msg->_ext_header); - } - - //print_session_stats ( _m_session ); - - - //printf ( "Payload: ( %d ) \n%s\n", _m_msg->_length, _m_msg->_data ); - - - } else if ( find_arg_simple ( _list, "-s" ) != FAILURE ) { - ip = find_arg_duble ( _list, "-d" ); - - if ( ip == NULL ) { - pthread_mutex_destroy ( &_mutex ); - return FAILURE; - } - - const char* _port = find_arg_duble ( _list, "-p" ); - - if ( _port != NULL ) { - port = atoi ( _port ); - } - - t_setipport ( ip, port, &Ip_port ); - printf ( "Remote: %s:%d\n", ip, port ); - - Networking_Core* _networking = new_networking(Ip_port.ip, RTP_PORT); - - if ( !_networking ){ - pthread_mutex_destroy ( &_mutex ); - return FAILURE; - } - - int _socket = _networking->sock; - - _m_session = rtp_init_session ( -1, -1 ); - rtp_add_receiver( _m_session, &Ip_port ); - //rtp_add_resolution_marking(_m_session, 1920, 1080); - //rtp_add_framerate_marking(_m_session, 1000); - - puts ( "Now sending payload!\n" ); - uint16_t _first_sequ = _m_session->_sequence_number; - - /* use already defined buffer lenght */ - while ( 1 ){ - _m_msg = rtp_msg_new ( _m_session, test_bytes, 300 ); - rtp_send_msg ( _m_session, _m_msg, _socket ); - usleep(10000); - } - - if ( _m_session->_last_error ) { - puts ( _m_session->_last_error ); - } - - return rtp_terminate_session(_m_session); - - } else { - pthread_mutex_destroy ( &_mutex ); - return FAILURE; - } - pthread_mutex_destroy ( &_mutex ); - - return SUCCESS; -} - -#endif /* _CT_HEADERS */ diff --git a/toxrtp/tests/test_helper.c b/toxrtp/tests/test_helper.c deleted file mode 100644 index 526b6b38..00000000 --- a/toxrtp/tests/test_helper.c +++ /dev/null @@ -1,83 +0,0 @@ -/* test_helper.c - * - * Tests support. !Red! - * - * - * 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 . - * - */ - -#include "test_helper.h" - -#include -#include - -arg_t* parse_args ( int argc, char* argv[] ) -{ - arg_t* _list = calloc(sizeof(arg_t), 1); - _list->next = _list->prev = NULL; - - arg_t* it = _list; - - size_t val; - for ( val = 0; val < argc; val ++ ) { - it->value = argv[val]; - - if ( val < argc - 1 ) { /* just about to end */ - it->next = calloc(sizeof(arg_t), 1); - it->next->prev = it; - it = it->next; - it->next = NULL; - } - } - - return _list; -} - -int find_arg_simple ( arg_t* _head, const char* _id ) -{ - arg_t* it = _head; - - int i; - for ( i = 1; it != NULL; it = it->next ) { - if ( strcmp ( _id, it->value ) == 0 ) { - return i; - } - - i++; - } - - return FAILURE; -} - -const char* find_arg_duble ( arg_t* _head, const char* _id ) -{ - arg_t* _it; - for ( _it = _head; _it != NULL; _it = _it->next ) { - if ( strcmp ( _id, _it->value ) == 0 ) { - if ( _it->next && _it->next->value[0] != '-' ) { /* exclude option */ - return _it->next->value; - } else { - return NULL; - } - } - } - - return NULL; -} - diff --git a/toxrtp/tests/test_helper.h b/toxrtp/tests/test_helper.h deleted file mode 100644 index de654743..00000000 --- a/toxrtp/tests/test_helper.h +++ /dev/null @@ -1,61 +0,0 @@ -/* test_helper.h - * - * Tests support. !Red! - * - * - * 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 _TEST__HELPER_ -#define _TEST__HELPER_ - -#include "../toxrtp_helper.h" - -#define RTP_PORT 31003 -#define RTP_PORT_LISTEN 31001 - -#define _SLEEP_INTERVAL 1000 - -typedef struct arg_s { - const char* value; - struct arg_s* next; - struct arg_s* prev; - -} arg_t; - - - -/* Parses arguments into d-list arg_t */ -arg_t* parse_args ( int argc, char* argv[] ); - -/* Get a single argument ( i.e. ./test -s |find if has 's' >> | find_arg_simple(_t, "-s") ) - * A little error checking, of course, returns FAILURE if not found and if found returns position - * where it's found. - */ -int find_arg_simple ( arg_t* _head, const char* _id ); - -/* Get a single argument ( i.e. ./test -d 127.0.0.1 |get 'd' value >> | find_arg_duble(_t, "-d") ) - * A little error checking, of course, returns NULL if not found and if found returns value - * of that argument ( i.e. '127.0.0.1'). - */ -const char* find_arg_duble ( arg_t* _head, const char* _id ); - -#endif /* _TEST__HELPER_ */ - - diff --git a/toxrtp/toxrtp.c b/toxrtp/toxrtp.c deleted file mode 100644 index 6844b0b1..00000000 --- a/toxrtp/toxrtp.c +++ /dev/null @@ -1,693 +0,0 @@ -/* rtp_impl.c - * - * Rtp implementation includes rtp_session_s struct which is a session identifier. - * It contains session information and it's a must for every session. - * It's best if you don't touch any variable directly but use callbacks to do so. !Red! - * - * - * 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 "toxrtp.h" -#include "toxrtp_message.h" -#include "toxrtp_helper.h" -#include -#include -#include "../toxcore/util.h" -#include "../toxcore/network.h" - -/* Some defines */ -#define PAYLOAD_ID_VALUE_OPUS 1 -#define PAYLOAD_ID_VALUE_VP8 2 - -#define size_32 4 -/* End of defines */ - -#ifdef _USE_ERRORS -#include "toxrtp_error_id.h" -#endif /* _USE_ERRORS */ - -static const uint32_t _payload_table[] = /* PAYLOAD TABLE */ -{ - 8000, 8000, 8000, 8000, 8000, 8000, 16000, 8000, 8000, 8000, /* 0-9 */ - 44100, 44100, 0, 0, 90000, 8000, 11025, 22050, 0, 0, /* 10-19 */ - 0, 0, 0, 0, 0, 90000, 90000, 0, 90000, 0, /* 20-29 */ - 0, 90000, 90000, 90000, 90000, 0, 0, 0, 0, 0, /* 30-39 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-49 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50-59 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-69 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70-79 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80-89 */ - 0, 0, 0, 0, 0, 0, PAYLOAD_ID_VALUE_OPUS, 0, 0, 0, /* 90-99 */ - 0, 0, 0, 0, 0, 0, PAYLOAD_ID_VALUE_VP8, 0, 0, 0, /* 100-109 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 110-119 */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 120-127 */ -}; - -/* Current compatibility solution */ -int m_sendpacket(Networking_Core* _core_handler, void *ip_port, uint8_t *data, uint32_t length) -{ - return sendpacket(_core_handler, *((IP_Port*) ip_port), data, length); -} - -rtp_session_t* rtp_init_session ( int max_users, int _multi_session ) -{ -#ifdef _USE_ERRORS - REGISTER_RTP_ERRORS -#endif /* _USE_ERRORS */ - - rtp_session_t* _retu = calloc(sizeof(rtp_session_t), 1); - assert(_retu); - - _retu->_dest_list = _retu->_last_user = NULL; - - _retu->_max_users = max_users; - _retu->_packets_recv = 0; - _retu->_packets_sent = 0; - _retu->_bytes_sent = 0; - _retu->_bytes_recv = 0; - _retu->_last_error = NULL; - _retu->_packet_loss = 0; - - /* - * SET HEADER FIELDS - */ - - _retu->_version = RTP_VERSION; /* It's always 2 */ - _retu->_padding = 0; /* If some additional data is needed about - * the packet */ - _retu->_extension = 0; /* If extension to header is needed */ - _retu->_cc = 1; /* It basically represents amount of contributors */ - _retu->_csrc = NULL; /* Container */ - _retu->_ssrc = t_random ( -1 ); - _retu->_marker = 0; - _retu->_payload_type = 0; /* You should specify payload type */ - - /* Sequence starts at random number and goes to _MAX_SEQU_NUM */ - _retu->_sequence_number = t_random ( _MAX_SEQU_NUM ); - _retu->_last_sequence_number = _retu->_sequence_number; /* Do not touch this variable */ - - _retu->_initial_time = t_time(); /* In seconds */ - assert(_retu->_initial_time); - _retu->_time_elapsed = 0; /* In seconds */ - - _retu->_ext_header = NULL; /* When needed allocate */ - _retu->_exthdr_framerate = -1; - _retu->_exthdr_resolution = -1; - - _retu->_csrc = calloc(sizeof(uint32_t), 1); - assert(_retu->_csrc); - - _retu->_csrc[0] = _retu->_ssrc; /* Set my ssrc to the list receive */ - - _retu->_prefix_length = 0; - _retu->_prefix = NULL; - - _retu->_multi_session = _multi_session; - - /* Initial */ - _retu->_current_framerate = 0; - - - _retu->_oldest_msg = _retu->_last_msg = NULL; - - pthread_mutex_init(&_retu->_mutex, NULL); - /* - * - */ - return _retu; -} - -int rtp_terminate_session ( rtp_session_t* _session ) -{ - if ( !_session ) - return FAILURE; - - if ( _session->_dest_list ){ - rtp_dest_list_t* _fordel = NULL; - rtp_dest_list_t* _tmp = _session->_dest_list; - - while( _tmp ){ - _fordel = _tmp; - _tmp = _tmp->next; - free(_fordel); - } - } - - if ( _session->_ext_header ) - free ( _session->_ext_header ); - - if ( _session->_csrc ) - free ( _session->_csrc ); - - if ( _session->_prefix ) - free ( _session->_prefix ); - - pthread_mutex_destroy(&_session->_mutex); - - /* And finally free session */ - free ( _session ); - - return SUCCESS; -} - -uint16_t rtp_get_resolution_marking_height ( rtp_ext_header_t* _header, uint32_t _position ) -{ - if ( _header->_ext_type & RTP_EXT_TYPE_RESOLUTION ) - return _header->_hd_ext[_position]; - else - return 0; -} - -uint16_t rtp_get_resolution_marking_width ( rtp_ext_header_t* _header, uint32_t _position ) -{ - if ( _header->_ext_type & RTP_EXT_TYPE_RESOLUTION ) - return ( _header->_hd_ext[_position] >> 16 ); - else - return 0; -} - -void rtp_free_msg ( rtp_session_t* _session, rtp_msg_t* _message ) -{ - free ( _message->_data ); - - if ( !_session ){ - free ( _message->_header->_csrc ); - if ( _message->_ext_header ){ - free ( _message->_ext_header->_hd_ext ); - free ( _message->_ext_header ); - } - } else { - if ( _session->_csrc != _message->_header->_csrc ) - free ( _message->_header->_csrc ); - if ( _message->_ext_header && _session->_ext_header != _message->_ext_header ) { - free ( _message->_ext_header->_hd_ext ); - free ( _message->_ext_header ); - } - } - - free ( _message->_header ); - free ( _message ); -} - -rtp_header_t* rtp_build_header ( rtp_session_t* _session ) -{ - rtp_header_t* _retu; - _retu = calloc ( sizeof * _retu, 1 ); - assert(_retu); - - rtp_header_add_flag_version ( _retu, _session->_version ); - rtp_header_add_flag_padding ( _retu, _session->_padding ); - rtp_header_add_flag_extension ( _retu, _session->_extension ); - rtp_header_add_flag_CSRC_count ( _retu, _session->_cc ); - rtp_header_add_setting_marker ( _retu, _session->_marker ); - rtp_header_add_setting_payload ( _retu, _session->_payload_type ); - - _retu->_sequence_number = _session->_sequence_number; - _session->_time_elapsed = t_time() - _session->_initial_time; - _retu->_timestamp = t_time(); - _retu->_ssrc = _session->_ssrc; - - if ( _session->_cc > 0 ) { - _retu->_csrc = calloc(sizeof(uint32_t), _session->_cc); - assert(_retu->_csrc); - - int i; - - for ( i = 0; i < _session->_cc; i++ ) { - _retu->_csrc[i] = _session->_csrc[i]; - } - } else { - _retu->_csrc = NULL; - } - - _retu->_length = _MIN_HEADER_LENGTH + ( _session->_cc * size_32 ); - - return _retu; -} - -void rtp_set_payload_type ( rtp_session_t* _session, uint8_t _payload_value ) -{ - _session->_payload_type = _payload_value; -} -uint32_t rtp_get_payload_type ( rtp_session_t* _session ) -{ - return _payload_table[_session->_payload_type]; -} - -int rtp_add_receiver ( rtp_session_t* _session, tox_IP_Port* _dest ) -{ - if ( !_session ) - return FAILURE; - - rtp_dest_list_t* _new_user = calloc(sizeof(rtp_dest_list_t), 1); - assert(_new_user); - - _new_user->next = NULL; - _new_user->_dest = *_dest; - - if ( _session->_last_user == NULL ) { /* New member */ - _session->_dest_list = _session->_last_user = _new_user; - - } else { /* Append */ - _session->_last_user->next = _new_user; - _session->_last_user = _new_user; - } - - return SUCCESS; -} - -int rtp_send_msg ( rtp_session_t* _session, rtp_msg_t* _msg, void* _core_handler ) -{ - if ( !_msg || _msg->_data == NULL || _msg->_length <= 0 ) { - t_perror ( RTP_ERROR_EMPTY_MESSAGE ); - return FAILURE; - } - - int _last; - unsigned long long _total = 0; - - size_t _length = _msg->_length; - uint8_t _send_data [ MAX_UDP_PACKET_SIZE ]; - - uint16_t _prefix_length = _session->_prefix_length; - - _send_data[0] = 70; - - if ( _session->_prefix && _length + _prefix_length < MAX_UDP_PACKET_SIZE ) { - /*t_memcpy(_send_data, _session->_prefix, _prefix_length);*/ - t_memcpy ( _send_data + 1, _msg->_data, _length ); - } else { - t_memcpy ( _send_data + 1, _msg->_data, _length ); - } - - /* Set sequ number */ - if ( _session->_sequence_number >= _MAX_SEQU_NUM ) { - _session->_sequence_number = 0; - } else { - _session->_sequence_number++; - } - - /* Start sending loop */ - rtp_dest_list_t* _it; - for ( _it = _session->_dest_list; _it != NULL; _it = _it->next ) { - - _last = m_sendpacket ( _core_handler, &_it->_dest, _send_data, _length + 1); - - if ( _last < 0 ) { - t_perror ( RTP_ERROR_STD_SEND_FAILURE ); - printf("Stderror: %s", strerror(errno)); - } else { - _session->_packets_sent ++; - _total += _last; - } - - } - - rtp_free_msg ( _session, _msg ); - _session->_bytes_sent += _total; - return SUCCESS; -} - -rtp_msg_t* rtp_recv_msg ( rtp_session_t* _session ) -{ - if ( !_session ) - return NULL; - - rtp_msg_t* _retu = _session->_oldest_msg; - - pthread_mutex_lock(&_session->_mutex); - - if ( _retu ) - _session->_oldest_msg = _retu->_next; - - if ( !_session->_oldest_msg ) - _session->_last_msg = NULL; - - pthread_mutex_unlock(&_session->_mutex); - - return _retu; -} - -void rtp_store_msg ( rtp_session_t* _session, rtp_msg_t* _msg ) -{ - if ( rtp_check_late_message(_session, _msg) < 0 ) { - rtp_register_msg(_session, _msg); - } - - pthread_mutex_lock(&_session->_mutex); - - if ( _session->_last_msg ) { - _session->_last_msg->_next = _msg; - _session->_last_msg = _msg; - } else { - _session->_last_msg = _session->_oldest_msg = _msg; - } - - pthread_mutex_unlock(&_session->_mutex); - return; -} - -int rtp_release_session_recv ( rtp_session_t* _session ) -{ - if ( !_session ){ - return FAILURE; - } - - rtp_msg_t* _tmp,* _it; - - pthread_mutex_lock(&_session->_mutex); - - for ( _it = _session->_oldest_msg; _it; _it = _tmp ){ - _tmp = _it->_next; - rtp_free_msg(_session, _it); - } - - _session->_last_msg = _session->_oldest_msg = NULL; - - pthread_mutex_unlock(&_session->_mutex); - - return SUCCESS; -} - -rtp_msg_t* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length ) -{ - if ( !_session ) - return NULL; - - uint8_t* _from_pos; - rtp_msg_t* _retu = calloc(sizeof(rtp_msg_t), 1); - assert(_retu); - - /* Sets header values and copies the extension header in _retu */ - _retu->_header = rtp_build_header ( _session ); /* It allocates memory and all */ - _retu->_ext_header = _session->_ext_header; - - uint32_t _total_lenght = _length + _retu->_header->_length; - - if ( _retu->_ext_header ) { - - _total_lenght += ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 ); - /* Allocate Memory for _retu->_data */ - _retu->_data = calloc ( sizeof _retu->_data, _total_lenght ); - assert(_retu->_data); - - _from_pos = rtp_add_header ( _retu->_header, _retu->_data ); - _from_pos = rtp_add_extention_header ( _retu->_ext_header, _from_pos + 1 ); - } else { - /* Allocate Memory for _retu->_data */ - _retu->_data = calloc ( sizeof _retu->_data, _total_lenght ); - assert(_retu->_data); - - _from_pos = rtp_add_header ( _retu->_header, _retu->_data ); - } - - /* - * Parses the extension header into the message - * Of course if any - */ - - /* Appends _data on to _retu->_data */ - t_memcpy ( _from_pos + 1, _data, _length ); - - _retu->_length = _total_lenght; - - _retu->_next = NULL; - - return _retu; -} - -rtp_msg_t* rtp_msg_parse ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length ) -{ - rtp_msg_t* _retu = calloc(sizeof(rtp_msg_t), 1); - assert(_retu); - - _retu->_header = rtp_extract_header ( _data, _length ); /* It allocates memory and all */ - if ( !_retu->_header ){ - free(_retu); - return NULL; - } - - _retu->_length = _length - _retu->_header->_length; - - uint16_t _from_pos = _retu->_header->_length; - - - if ( rtp_header_get_flag_extension ( _retu->_header ) ) { - _retu->_ext_header = rtp_extract_ext_header ( _data + _from_pos, _length ); - if ( _retu->_ext_header ){ - _retu->_length -= ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 ); - _from_pos += ( _MIN_EXT_HEADER_LENGTH + _retu->_ext_header->_ext_len * size_32 ); - } else { - free (_retu->_ext_header); - free (_retu->_header); - free (_retu); - return NULL; - } - } else { - _retu->_ext_header = NULL; - } - - /* Get the payload */ - _retu->_data = calloc ( sizeof ( uint8_t ), _retu->_length ); - assert(_retu->_data); - - t_memcpy ( _retu->_data, _data + _from_pos, _length - _from_pos ); - - _retu->_next = NULL; - - - if ( _session && !_session->_multi_session && rtp_check_late_message(_session, _retu) < 0 ){ - rtp_register_msg(_session, _retu); - } - - return _retu; -} - -int rtp_check_late_message (rtp_session_t* _session, rtp_msg_t* _msg) -{ - /* - * Check Sequence number. If this new msg has lesser number then the _session->_last_sequence_number - * it shows that the message came in late - */ - if ( _msg->_header->_sequence_number < _session->_last_sequence_number && - _msg->_header->_timestamp < _session->_current_timestamp - ) { - return SUCCESS; /* Drop the packet. You can check if the packet dropped by checking _packet_loss increment. */ - } - return FAILURE; -} - -void rtp_register_msg ( rtp_session_t* _session, rtp_msg_t* _msg ) -{ - _session->_last_sequence_number = _msg->_header->_sequence_number; - _session->_current_timestamp = _msg->_header->_timestamp; -} - - -int rtp_add_resolution_marking ( rtp_session_t* _session, uint16_t _width, uint16_t _height ) -{ - if ( !_session ) - return FAILURE; - - rtp_ext_header_t* _ext_header = _session->_ext_header; - _session->_exthdr_resolution = 0; - - if ( ! ( _ext_header ) ) { - _session->_ext_header = calloc (sizeof(rtp_ext_header_t), 1); - assert(_session->_ext_header); - - _session->_extension = 1; - _session->_ext_header->_ext_len = 1; - _ext_header = _session->_ext_header; - _session->_ext_header->_hd_ext = calloc(sizeof(uint32_t), 1); - assert(_session->_ext_header->_hd_ext); - - } else { /* If there is need for more headers this will be needed to change */ - if ( !(_ext_header->_ext_type & RTP_EXT_TYPE_RESOLUTION) ){ - uint32_t _exthdr_framerate = _ext_header->_hd_ext[_session->_exthdr_framerate]; - /* it's position is at 2nd place by default */ - _session->_exthdr_framerate ++; - - /* Update length */ - _ext_header->_ext_len++; - - /* Allocate the value */ - _ext_header->_hd_ext = realloc(_ext_header->_hd_ext, sizeof(rtp_ext_header_t) * _ext_header->_ext_len); - assert(_ext_header->_hd_ext); - - /* Reset other values */ - _ext_header->_hd_ext[_session->_exthdr_framerate] = _exthdr_framerate; - } - } - - /* Add flag */ - _ext_header->_ext_type |= RTP_EXT_TYPE_RESOLUTION; - - _ext_header->_hd_ext[_session->_exthdr_resolution] = _width << 16 | ( uint32_t ) _height; - - return SUCCESS; -} - -int rtp_remove_resolution_marking ( rtp_session_t* _session ) -{ - if ( _session->_extension == 0 || ! ( _session->_ext_header ) ) { - t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER ); - return FAILURE; - } - - if ( !( _session->_ext_header->_ext_type & RTP_EXT_TYPE_RESOLUTION ) ) { - t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER ); - return FAILURE; - } - - _session->_ext_header->_ext_type &= ~RTP_EXT_TYPE_RESOLUTION; /* Remove the flag */ - _session->_exthdr_resolution = -1; /* Remove identifier */ - - /* Check if extension is empty */ - if ( _session->_ext_header->_ext_type == 0 ){ - - free ( _session->_ext_header->_hd_ext ); - free ( _session->_ext_header ); - - _session->_ext_header = NULL; /* It's very important */ - _session->_extension = 0; - - } else { - _session->_ext_header->_ext_len --; - - /* this will also be needed to change if there are more than 2 headers */ - if ( _session->_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE ){ - memcpy(_session->_ext_header->_hd_ext + 1, _session->_ext_header->_hd_ext, _session->_ext_header->_ext_len); - _session->_exthdr_framerate = 0; - _session->_ext_header->_hd_ext = realloc( _session->_ext_header->_hd_ext, sizeof( rtp_ext_header_t ) * _session->_ext_header->_ext_len ); - assert(_session->_ext_header->_hd_ext); - } - } - - return SUCCESS; -} - -int rtp_add_framerate_marking ( rtp_session_t* _session, uint32_t _value ) -{ - if ( !_session ) - return FAILURE; - - rtp_ext_header_t* _ext_header = _session->_ext_header; - _session->_exthdr_framerate = 0; - - if ( ! ( _ext_header ) ) { - _session->_ext_header = calloc (sizeof(rtp_ext_header_t), 1); - assert(_session->_ext_header); - - _session->_extension = 1; - _session->_ext_header->_ext_len = 1; - _ext_header = _session->_ext_header; - _session->_ext_header->_hd_ext = calloc(sizeof(uint32_t), 1); - assert(_session->_ext_header->_hd_ext); - } else { /* If there is need for more headers this will be needed to change */ - if ( !(_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE) ){ - /* it's position is at 2nd place by default */ - _session->_exthdr_framerate ++; - - /* Update length */ - _ext_header->_ext_len++; - - /* Allocate the value */ - _ext_header->_hd_ext = realloc(_ext_header->_hd_ext, sizeof(rtp_ext_header_t) * _ext_header->_ext_len); - assert(_ext_header->_hd_ext); - - } - } - - /* Add flag */ - _ext_header->_ext_type |= RTP_EXT_TYPE_FRAMERATE; - - _ext_header->_hd_ext[_session->_exthdr_framerate] = _value; - - return SUCCESS; -} - - -int rtp_remove_framerate_marking ( rtp_session_t* _session ) -{ - if ( _session->_extension == 0 || ! ( _session->_ext_header ) ) { - t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER ); - return FAILURE; - } - - if ( !( _session->_ext_header->_ext_type & RTP_EXT_TYPE_FRAMERATE ) ) { - t_perror ( RTP_ERROR_INVALID_EXTERNAL_HEADER ); - return FAILURE; - } - - _session->_ext_header->_ext_type &= ~RTP_EXT_TYPE_FRAMERATE; /* Remove the flag */ - _session->_exthdr_framerate = -1; /* Remove identifier */ - _session->_ext_header->_ext_len --; - - /* Check if extension is empty */ - if ( _session->_ext_header->_ext_type == 0 ){ - - free ( _session->_ext_header->_hd_ext ); - free ( _session->_ext_header ); - - _session->_ext_header = NULL; /* It's very important */ - _session->_extension = 0; - - } else if ( !_session->_ext_header->_ext_len ) { - - /* this will also be needed to change if there are more than 2 headers */ - _session->_ext_header->_hd_ext = realloc( _session->_ext_header->_hd_ext, sizeof( rtp_ext_header_t ) * _session->_ext_header->_ext_len ); - assert(_session->_ext_header->_hd_ext); - - } - - return SUCCESS; -} - -uint32_t rtp_get_framerate_marking ( rtp_ext_header_t* _header ) -{ - if ( _header->_ext_len == 1 ){ - return _header->_hd_ext[0]; - } else { - return _header->_hd_ext[1]; - } -} - -int rtp_set_prefix ( rtp_session_t* _session, uint8_t* _prefix, uint16_t _prefix_length ) -{ - if ( !_session ) - return FAILURE; - - if ( _session->_prefix ) { - free ( _session->_prefix ); - } - - _session->_prefix = calloc ( ( sizeof * _session->_prefix ), _prefix_length ); - assert(_session->_prefix); - - t_memcpy ( _session->_prefix, _prefix, _prefix_length ); - _session->_prefix_length = _prefix_length; - - return SUCCESS; -} diff --git a/toxrtp/toxrtp.h b/toxrtp/toxrtp.h deleted file mode 100644 index 0aa89993..00000000 --- a/toxrtp/toxrtp.h +++ /dev/null @@ -1,188 +0,0 @@ -/* rtp_impl.h - * - * Rtp implementation includes rtp_session_s struct which is a session identifier. - * It contains session information and it's a must for every session. - * It's best if you don't touch any variable directly but use callbacks to do so. !Red! - * - * - * 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 _RTP__IMPL_H_ -#define _RTP__IMPL_H_ - -#define RTP_VERSION 2 -#include -#include "tox.h" -#include -/* Extension header flags */ -#define RTP_EXT_TYPE_RESOLUTION 0x01 -#define RTP_EXT_TYPE_FRAMERATE 0x02 - -/* Some defines */ - -#define RTP_PACKET 70 - -/* Payload identifiers */ - -/* Audio */ -#define _PAYLOAD_OPUS 96 - -/* Video */ -#define _PAYLOAD_VP8 106 - -/* End of Payload identifiers */ - -/* End of defines */ - - -/* Our main session descriptor. - * It measures the session variables and controls - * the entire session. There are functions for manipulating - * the session so tend to use those instead of directly accessing - * session parameters. - */ -typedef struct rtp_session_s { - uint8_t _version; - uint8_t _padding; - uint8_t _extension; - uint8_t _cc; - uint8_t _marker; - uint8_t _payload_type; - uint16_t _sequence_number; /* Set when sending */ - uint16_t _last_sequence_number; /* Check when recving msg */ - uint32_t _initial_time; - uint32_t _time_elapsed; - uint32_t _current_timestamp; - uint32_t _ssrc; - uint32_t *_csrc; - - - /* If some additional data must be sent via message - * apply it here. Only by allocating this member you will be - * automatically placing it within a message. - */ - - struct rtp_ext_header_s *_ext_header; - /* External header identifiers */ - int _exthdr_resolution; - int _exthdr_framerate; - - int _max_users; /* -1 undefined */ - - uint64_t _packets_sent; /* measure packets */ - uint64_t _packets_recv; - - uint64_t _bytes_sent; - uint64_t _bytes_recv; - - uint64_t _packet_loss; - - const char *_last_error; - - struct rtp_dest_list_s *_dest_list; - struct rtp_dest_list_s *_last_user; /* a tail for faster appending */ - - struct rtp_msg_s *_oldest_msg; - struct rtp_msg_s *_last_msg; /* tail */ - - uint16_t _prefix_length; - uint8_t *_prefix; - - /* Specifies multiple session use. - * When using one session it uses default value ( -1 ) - * Otherwise it's set to 1 and rtp_register_msg () is required - */ - int _multi_session; - - uint32_t _current_framerate; - - pthread_mutex_t _mutex; - -} rtp_session_t; - - -/* - * Now i don't believe we need to store this _from thing every time - * since we have csrc table but will leave it like this for a while - */ - - -void rtp_free_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg ); -int rtp_release_session_recv ( rtp_session_t *_session ); - -/* Functions handling receiving */ -struct rtp_msg_s *rtp_recv_msg ( rtp_session_t *_session ); -void rtp_store_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg ); - -/* - * rtp_msg_parse() stores headers separately from the payload data - * and so the _length variable is set accordingly - */ -struct rtp_msg_s *rtp_msg_parse ( rtp_session_t *_session, const uint8_t *_data, uint32_t _length ); - -int rtp_check_late_message (rtp_session_t *_session, struct rtp_msg_s *_msg); -void rtp_register_msg ( rtp_session_t *_session, struct rtp_msg_s * ); - -/* Functions handling sending */ -int rtp_send_msg ( rtp_session_t *_session, struct rtp_msg_s *_msg, void *_core_handler ); - -/* - * rtp_msg_new() stores headers and payload data in one container ( _data ) - * and the _length is set accordingly. Returned message is used for sending only - * so there is not much use of the headers there - */ -struct rtp_msg_s *rtp_msg_new ( rtp_session_t *_session, const uint8_t *_data, uint32_t _length ); - - -/* Convenient functions for creating a header */ -struct rtp_header_s *rtp_build_header ( rtp_session_t *_session ); - -/* Functions handling session control */ - -/* Handling an rtp packet */ -/* int rtp_handlepacket(uint8_t * packet, uint32_t length, IP_Port source); */ - -/* Session initiation and termination. - * Set _multi_session to -1 if not using multiple sessions - */ -rtp_session_t *rtp_init_session ( int _max_users, int _multi_session ); -int rtp_terminate_session ( rtp_session_t *_session ); - -/* Adding receiver */ -int rtp_add_receiver ( rtp_session_t *_session, tox_IP_Port *_dest ); - -/* Convenient functions for marking the resolution */ -int rtp_add_resolution_marking ( rtp_session_t *_session, uint16_t _width, uint16_t _height ); -int rtp_remove_resolution_marking ( rtp_session_t *_session ); -uint16_t rtp_get_resolution_marking_height ( struct rtp_ext_header_s *_header, uint32_t _position ); -uint16_t rtp_get_resolution_marking_width ( struct rtp_ext_header_s *_header, uint32_t _position ); - -int rtp_add_framerate_marking ( rtp_session_t *_session, uint32_t _value ); -int rtp_remove_framerate_marking ( rtp_session_t *_session ); -uint32_t rtp_get_framerate_marking ( struct rtp_ext_header_s *_header ); -/* Convenient functions for marking the payload */ -void rtp_set_payload_type ( rtp_session_t *_session, uint8_t _payload_value ); -uint32_t rtp_get_payload_type ( rtp_session_t *_session ); - -/* When using RTP in core be sure to set prefix when sending via rtp_send_msg */ -int rtp_set_prefix ( rtp_session_t *_session, uint8_t *_prefix, uint16_t _prefix_length ); - -#endif /* _RTP__IMPL_H_ */ diff --git a/toxrtp/toxrtp_error.c b/toxrtp/toxrtp_error.c deleted file mode 100644 index 3a7ff9a5..00000000 --- a/toxrtp/toxrtp_error.c +++ /dev/null @@ -1,68 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#include "toxrtp_error.h" -#include "toxrtp_helper.h" - -#include -#include -#include -#include -#include - -typedef struct rtp_error_s { - char* _message; - int _id; - -} rtp_error_t; - -static rtp_error_t* _register = NULL; -static size_t _it = 0; - -void t_rtperr_register ( int _id, const char* _info ) -{ - size_t _info_size = strlen ( _info ); - - if ( !_register ) { - _register = calloc ( sizeof ( rtp_error_t ), 1 ); - } else { - _register = realloc ( _register, sizeof ( rtp_error_t ) * ( _it + 1 ) ); - } - assert(_register); - - - rtp_error_t* _current = & _register[_it]; - - _current->_id = _id; - _current->_message = calloc ( sizeof(char), _info_size ); - assert(_current->_message); - - t_memcpy ( (uint8_t*)_current->_message, (const uint8_t*)_info, _info_size ); - _it ++; -} - -const char* t_rtperr ( int _errno ) -{ - if ( !_register ) - return "Unregistered"; - - uint32_t _i; - - for ( _i = _it; _i--; ) { - if ( _register[_i]._id == _errno ) { - return _register[_i]._message; - } - } - - return "Invalid error id!"; -} - -void t_rtperr_print ( const char* _val, ... ) -{ - va_list _args; - va_start ( _args, _val ); - vfprintf ( stderr, _val, _args ); - va_end ( _args ); -} diff --git a/toxrtp/toxrtp_error.h b/toxrtp/toxrtp_error.h deleted file mode 100644 index 0e017246..00000000 --- a/toxrtp/toxrtp_error.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _RTP_ERROR_ -#define _RTP_ERROR_ - -#define PRINT_FORMAT "Error %d: %s at %s:%d\n" -#define PRINT_ARGS( _errno ) _errno, t_rtperr(_errno), __FILE__, __LINE__ - - -const char* t_rtperr ( int _errno ); -void t_rtperr_register ( int _id, const char* _info ); - -void t_invoke_error ( int _id ); -void t_rtperr_print ( const char* _val, ... ); - - -#ifdef _USE_ERRORS -#define t_perror( _errno ) t_rtperr_print ( PRINT_FORMAT, PRINT_ARGS ( _errno ) ) -#else -#define t_perror( _errno )do { } while(0) -#endif /* _USE_ERRORS */ - -#ifdef _STDIO_H -#define t_errexit( _errno ) exit(-_errno) -#endif /* _STDIO_H */ - -#endif /* _RTP_ERROR_ */ diff --git a/toxrtp/toxrtp_error_id.h b/toxrtp/toxrtp_error_id.h deleted file mode 100644 index 201aa936..00000000 --- a/toxrtp/toxrtp_error_id.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _RTP_ERROR_ID_ -#define _RTP_ERROR_ID_ - -#include "toxrtp_error.h" - -typedef enum error_s { - RTP_ERROR_PACKET_DROPED = 1, - RTP_ERROR_EMPTY_MESSAGE, - RTP_ERROR_STD_SEND_FAILURE, - RTP_ERROR_NO_EXTERNAL_HEADER, - RTP_ERROR_INVALID_EXTERNAL_HEADER, - RTP_ERROR_HEADER_PARSING, - RTP_ERROR_PAYLOAD_NULL, - RTP_ERROR_PAYLOAD_INVALID, - -} error_t; - - -/* Only needed to be called once */ -#ifndef REGISTER_RTP_ERRORS -#define REGISTER_RTP_ERRORS \ - t_rtperr_register( RTP_ERROR_PACKET_DROPED, "Ivalid sequence number, packet is late" ); \ - t_rtperr_register( RTP_ERROR_EMPTY_MESSAGE, "Tried to send an empty message" ); \ - t_rtperr_register( RTP_ERROR_STD_SEND_FAILURE, "Failed call function: sendto" ); \ - t_rtperr_register( RTP_ERROR_NO_EXTERNAL_HEADER, "While parsing external header" ); \ - t_rtperr_register( RTP_ERROR_INVALID_EXTERNAL_HEADER, "While parsing external header" ); \ - t_rtperr_register( RTP_ERROR_HEADER_PARSING, "While parsing header" ); \ - t_rtperr_register( RTP_ERROR_PAYLOAD_NULL, "Payload is NULL" ); \ - t_rtperr_register( RTP_ERROR_PAYLOAD_INVALID, "Invalid payload size" ); -#endif /* REGISTER_RTP_ERRORS */ - -#endif /* _RTP_ERROR_ID_ */ diff --git a/toxrtp/toxrtp_helper.c b/toxrtp/toxrtp_helper.c deleted file mode 100644 index 6f952359..00000000 --- a/toxrtp/toxrtp_helper.c +++ /dev/null @@ -1,208 +0,0 @@ -/* rtp_helper.c -* -* Has some standard functions. !Red! -* -* -* 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 "toxrtp_helper.h" -#include "../toxcore/network.h" - -#include - -#ifdef WIN -#include -#endif /* WIN */ - - -static int _seed = 0; /* Not initiated */ - -int t_setipport ( const char *_ip, unsigned short _port, void *_dest ) -{ - assert(_dest); - - IP_Port *_dest_c = ( IP_Port * ) _dest; - ip_init(&_dest_c->ip, 0); - - IP_Port _ipv6_garbage; - - if ( !addr_resolve(_ip, &_dest_c->ip, &_ipv6_garbage.ip) ) - return FAILURE; - - _dest_c->port = htons ( _port ); - - return SUCCESS; -} - -uint32_t t_random ( uint32_t _max ) -{ - if ( !_seed ) { - srand ( t_time() ); - _seed++; - } - - if ( _max <= 0 ) { - return ( unsigned ) rand(); - } else { - return ( unsigned ) rand() % _max; - } -} - -void t_memcpy ( uint8_t *_dest, const uint8_t *_source, size_t _size ) -{ - /* - * Using countdown to zero method - * It's faster than for(_it = 0; _it < _size; _it++); - */ - size_t _it = _size; - - do { - _it--; - _dest[_it] = _source[_it]; - } while ( _it ); - -} - -uint8_t *t_memset ( uint8_t *_dest, uint8_t _valu, size_t _size ) -{ - /* - * Again using countdown to zero method - */ - size_t _it = _size; - - do { - _it--; - _dest[_it] = _valu; - } while ( _it ); - - return _dest; -} - -size_t t_memlen ( const uint8_t *_valu) -{ - const uint8_t *_it; - size_t _retu = 0; - - for ( _it = _valu; *_it; ++_it ) ++_retu; - - return _retu; -} - -uint8_t *t_strallcpy ( const uint8_t *_source ) /* string alloc and copy */ -{ - assert(_source); - - size_t _length = t_memlen(_source) + 1; /* make space for null character */ - - uint8_t *_dest = calloc( sizeof ( uint8_t ), _length ); - assert(_dest); - - t_memcpy(_dest, _source, _length); - - return _dest; -} - -size_t t_strfind ( const uint8_t *_str, const uint8_t *_substr ) -{ - size_t _pos = 0; - size_t _it, _delit = 0; - - for ( _it = 0; _str[_it] != '\0'; _it++ ) { - if ( _str[_it] == _substr[_delit] ) { - _pos = _it; - - while ( _str[_it] == _substr[_delit] && _str[_it] != '\0' ) { - _it ++; - _delit++; - - if ( _substr[_delit] == '\0' ) { - return _pos; - } - } - - _delit = 0; - _pos = 0; - } - } - - return _pos; -} - -#ifdef WIN -#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) -#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 -#else -#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL -#endif - -struct timezone { - int tz_minuteswest; /* minutes W of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -int gettimeofday(struct timeval *tv, struct timezone *tz) -{ - FILETIME ft; - unsigned __int64 tmpres = 0; - static int tzflag; - - if (NULL != tv) { - GetSystemTimeAsFileTime(&ft); - - tmpres |= ft.dwHighDateTime; - tmpres <<= 32; - tmpres |= ft.dwLowDateTime; - - /*converting file time to unix epoch*/ - tmpres -= DELTA_EPOCH_IN_MICROSECS; - tmpres /= 10; /*convert into microseconds*/ - tv->tv_sec = (long)(tmpres / 1000000UL); - tv->tv_usec = (long)(tmpres % 1000000UL); - } - - if (NULL != tz) { - if (!tzflag) { - _tzset(); - tzflag++; - } - - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - - return 0; -} -#endif /* WIN */ - - -uint64_t t_time() -{ - struct timeval _tv; - gettimeofday(&_tv, NULL); - uint64_t _retu_usec = _tv.tv_sec % 1000000; /* get 6 digits an leave space for 3 more */ - _retu_usec = _retu_usec * 1000 + (_tv.tv_usec / 1000 ); - return _retu_usec; -} diff --git a/toxrtp/toxrtp_helper.h b/toxrtp/toxrtp_helper.h deleted file mode 100644 index c9bcfcca..00000000 --- a/toxrtp/toxrtp_helper.h +++ /dev/null @@ -1,77 +0,0 @@ -/* rtp_helper.h -* -* Has some standard functions. !Red! -* -* -* 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 _RTP__HELPER_H_ -#define _RTP__HELPER_H_ - -#include -#include - -/* Current time, unix format */ -/*#define _time ((uint32_t)time(NULL))*/ - -#define SUCCESS 0 -#define FAILURE -1 - -#define _USE_ERRORS - -#define RUN_IN_THREAD(_func, _thread_id, _arg_ptr) \ -if ( pthread_create ( &_thread_id, NULL, _func, _arg_ptr ) ) { \ - pthread_detach ( _thread_id ); \ -} - -/* Core adaptation helper */ -int t_setipport ( const char* _ip, unsigned short _port, void* _cont ); -uint32_t t_random ( uint32_t _max ); - -/* It's a bit faster than the memcpy it self and more optimized for using - * a uint8_t since memcpy has optimizations when copying "words" i.e. long type. - * Otherwise it just copies char's while we need only uint8_t - */ -void t_memcpy ( uint8_t* _dest, const uint8_t* _source, size_t _size ); - - -/* This is our memset. It's also a bit faster than the memset for it - * does not cast _dest to char* and uses faster loop algorithm. - */ -uint8_t* t_memset ( uint8_t* _dest, uint8_t _valu, size_t _size ); - -/* Get null terminated len */ -size_t t_memlen ( const uint8_t* _valu ); - -/* finds location of substring */ -size_t t_strfind ( const uint8_t* _str, const uint8_t* _substr ); - -/* string alloc and copy ( ! must be null terminated ) */ -uint8_t* t_strallcpy ( const uint8_t* _source ); - -/* Get current time in milliseconds */ -uint64_t t_time(); - - -#endif /* _RTP__HELPER_H_ */ - - - - diff --git a/toxrtp/toxrtp_message.c b/toxrtp/toxrtp_message.c deleted file mode 100644 index e7f1f2c0..00000000 --- a/toxrtp/toxrtp_message.c +++ /dev/null @@ -1,351 +0,0 @@ -/* rtp_message.c - * - * Rtp Message handler. It handles message/header parsing. - * Refer to RTP: A Transport Protocol for Real-Time Applications ( RFC 3550 ) for more info. !Red! - * - * - * 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 "toxrtp_message.h" -#include "toxrtp.h" -#include - -#ifdef _USE_ERRORS -#include "toxrtp_error_id.h" -#endif /* _USE_ERRORS */ - -#include - -/* Some defines */ - -/* End of defines */ - -void rtp_header_print (const rtp_header_t* _header) -{ - printf("Header: \n" - "Version: %d\n" - "Padding: %d\n" - "Ext: %d\n" - "CC: %d\n" - "marker: %d\n" - "payload typ:%d\n\n" - "sequ num: %d\n" - "Timestamp: %d\n" - "SSrc: %d\n" - "CSrc: %d\n" - "Lenght: %d\n" - ,rtp_header_get_flag_version(_header) - ,rtp_header_get_flag_padding(_header) - ,rtp_header_get_flag_extension(_header) - ,rtp_header_get_flag_CSRC_count(_header) - ,rtp_header_get_setting_marker(_header) - ,rtp_header_get_setting_payload_type(_header) - ,_header->_sequence_number - ,_header->_timestamp - ,_header->_ssrc - ,_header->_csrc[0] - ,_header->_length - ); -} - -rtp_header_t* rtp_extract_header ( const uint8_t* _payload, size_t _bytes ) -{ - if ( !_payload ) { - t_perror ( RTP_ERROR_PAYLOAD_NULL ); - return NULL; - } - const uint8_t* _it = _payload; - - rtp_header_t* _retu = calloc(sizeof(rtp_header_t), 1); - assert(_retu); - - _retu->_flags = *_it; ++_it; - - /* This indicates if the first 2 bytes are valid. - * Now it my happen that this is out of order but - * it cuts down chances of parsing some invalid value - */ - if ( rtp_header_get_flag_version(_retu) != RTP_VERSION ){ - printf("Invalid version: %d\n", rtp_header_get_flag_version(_retu)); - //assert(rtp_header_get_flag_version(_retu) == RTP_VERSION); - /* Deallocate */ - //DEALLOCATOR(_retu); - //return NULL; - } - - /* - * Added a check for the size of the header little sooner so - * I don't need to parse the other stuff if it's bad - */ - uint8_t cc = rtp_header_get_flag_CSRC_count ( _retu ); - uint32_t _lenght = _MIN_HEADER_LENGTH + ( cc * 4 ); - - if ( _bytes < _lenght ) { - t_perror ( RTP_ERROR_PAYLOAD_INVALID ); - return NULL; - } - - if ( cc > 0 ) { - _retu->_csrc = calloc ( sizeof ( uint32_t ), cc ); - assert(_retu->_csrc); - - } else { /* But this should not happen ever */ - t_perror ( RTP_ERROR_HEADER_PARSING ); - return NULL; - } - - - _retu->_marker_payload_t = *_it; ++_it; - _retu->_length = _lenght; - _retu->_sequence_number = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); - - _it += 2; - - _retu->_timestamp = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( * ( _it + 3 ) ) ; - - _it += 4; - - _retu->_ssrc = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; - - - size_t x; - for ( x = 0; x < cc; x++ ) { - _it += 4; - _retu->_csrc[x] = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; - } - - return _retu; -} - -rtp_ext_header_t* rtp_extract_ext_header ( const uint8_t* _payload, size_t _bytes ) -{ - if ( !_payload ) { - t_perror ( RTP_ERROR_PAYLOAD_NULL ); - return NULL; - } - - - - const uint8_t* _it = _payload; - - rtp_ext_header_t* _retu = calloc(sizeof(rtp_ext_header_t), 1); - assert(_retu); - - uint16_t _ext_len = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it += 2; - - if ( _bytes < ( _ext_len * sizeof(uint32_t) ) ) { - t_perror ( RTP_ERROR_PAYLOAD_INVALID ); - return NULL; - } - - _retu->_ext_len = _ext_len; - _retu->_ext_type = ( ( uint16_t ) * _it << 8 ) | * ( _it + 1 ); _it -= 2; - - _retu->_hd_ext = calloc(sizeof(uint32_t), _ext_len); - assert(_retu->_hd_ext); - - uint32_t* _hd_ext = _retu->_hd_ext; - size_t i; - for ( i = 0; i < _ext_len; i++ ) { - _it += 4; - _hd_ext[i] = ( ( uint32_t ) * _it << 24 ) | - ( ( uint32_t ) * ( _it + 1 ) << 16 ) | - ( ( uint32_t ) * ( _it + 2 ) << 8 ) | - ( ( uint32_t ) * ( _it + 3 ) ) ; - } - - return _retu; -} - -uint8_t* rtp_add_header ( rtp_header_t* _header, uint8_t* _payload ) -{ - uint8_t cc = rtp_header_get_flag_CSRC_count ( _header ); - - uint8_t* _it = _payload; - - *_it = _header->_flags; ++_it; - *_it = _header->_marker_payload_t; ++_it; - - *_it = ( _header->_sequence_number >> 8 ); ++_it; - *_it = ( _header->_sequence_number ); ++_it; - - uint32_t _timestamp = _header->_timestamp; - *_it = ( _timestamp >> 24 ); ++_it; - *_it = ( _timestamp >> 16 ); ++_it; - *_it = ( _timestamp >> 8 ); ++_it; - *_it = ( _timestamp ); ++_it; - - uint32_t _ssrc = _header->_ssrc; - *_it = ( _ssrc >> 24 ); ++_it; - *_it = ( _ssrc >> 16 ); ++_it; - *_it = ( _ssrc >> 8 ); ++_it; - *_it = ( _ssrc ); - - uint32_t *_csrc = _header->_csrc; - size_t x; - for ( x = 0; x < cc; x++ ) { - ++_it; - *_it = ( _csrc[x] >> 24 ); ++_it; - *_it = ( _csrc[x] >> 16 ); ++_it; - *_it = ( _csrc[x] >> 8 ); ++_it; - *_it = ( _csrc[x] ); - } - - return _it; -} - -uint8_t* rtp_add_extention_header ( rtp_ext_header_t* _header, uint8_t* _payload ) -{ - uint8_t* _it = _payload; - - *_it = ( _header->_ext_len >> 8 ); _it++; - *_it = ( _header->_ext_len ); _it++; - - *_it = ( _header->_ext_type >> 8 ); ++_it; - *_it = ( _header->_ext_type ); - - size_t x; - - uint32_t* _hd_ext = _header->_hd_ext; - for ( x = 0; x < _header->_ext_len; x++ ) { - ++_it; - *_it = ( _hd_ext[x] >> 24 ); ++_it; - *_it = ( _hd_ext[x] >> 16 ); ++_it; - *_it = ( _hd_ext[x] >> 8 ); ++_it; - *_it = ( _hd_ext[x] ); - } - - return _it; -} - -size_t rtp_header_get_size ( const rtp_header_t* _header ) -{ - return ( 8 + ( rtp_header_get_flag_CSRC_count ( _header ) * 4 ) ); -} -/* Setting flags */ - -void rtp_header_add_flag_version ( rtp_header_t* _header, uint32_t value ) -{ - ( _header->_flags ) &= 0x3F; - ( _header->_flags ) |= ( ( ( value ) << 6 ) & 0xC0 ); -} - -void rtp_header_add_flag_padding ( rtp_header_t* _header, uint32_t value ) -{ - if ( value > 0 ) { - value = 1; /* It can only be 1 */ - } - - ( _header->_flags ) &= 0xDF; - ( _header->_flags ) |= ( ( ( value ) << 5 ) & 0x20 ); -} - -void rtp_header_add_flag_extension ( rtp_header_t* _header, uint32_t value ) -{ - if ( value > 0 ) { - value = 1; /* It can only be 1 */ - } - - ( _header->_flags ) &= 0xEF; - ( _header->_flags ) |= ( ( ( value ) << 4 ) & 0x10 ); -} - -void rtp_header_add_flag_CSRC_count ( rtp_header_t* _header, uint32_t value ) -{ - ( _header->_flags ) &= 0xF0; - ( _header->_flags ) |= ( ( value ) & 0x0F ); -} - -void rtp_header_add_setting_marker ( rtp_header_t* _header, uint32_t value ) -{ - if ( value > 1 ) - value = 1; - - ( _header->_marker_payload_t ) &= 0x7F; - ( _header->_marker_payload_t ) |= ( ( ( value ) << 7 ) /*& 0x80 */ ); -} - -void rtp_header_add_setting_payload ( rtp_header_t* _header, uint32_t value ) -{ - if ( value > 127 ) - value = 127; /* Well set to maximum */ - - ( _header->_marker_payload_t ) &= 0x80; - ( _header->_marker_payload_t ) |= ( ( value ) /* & 0x7F */ ); -} - -/* Getting values from flags */ -uint8_t rtp_header_get_flag_version ( const rtp_header_t* _header ) -{ - return ( _header->_flags & 0xd0 ) >> 6; -} - -uint8_t rtp_header_get_flag_padding ( const rtp_header_t* _header ) -{ - return ( _header->_flags & 0x20 ) >> 5; -} - -uint8_t rtp_header_get_flag_extension ( const rtp_header_t* _header ) -{ - return ( _header->_flags & 0x10 ) >> 4; -} - -uint8_t rtp_header_get_flag_CSRC_count ( const rtp_header_t* _header ) -{ - return ( _header->_flags & 0x0f ); -} -uint8_t rtp_header_get_setting_marker ( const rtp_header_t* _header ) -{ - return ( _header->_marker_payload_t ) >> 7; -} -uint8_t rtp_header_get_setting_payload_type ( const rtp_header_t* _header ) -{ - /* - uint8_t _retu; - - if ( _header->_marker_payload_t >> 7 == 1 ) { - _header->_marker_payload_t ^= 0x80; - _retu = _header->_marker_payload_t; - _header->_marker_payload_t ^= 0x80; - } else { - _retu = _header->_marker_payload_t; - } - */ - /* return to start value - return _retu; */ - return _header->_marker_payload_t & 0x7f; -} - -/* */ - - diff --git a/toxrtp/toxrtp_message.h b/toxrtp/toxrtp_message.h deleted file mode 100644 index 8feea5d9..00000000 --- a/toxrtp/toxrtp_message.h +++ /dev/null @@ -1,111 +0,0 @@ -/* rtp_message.h - * - * Rtp Message handler. It handles message/header parsing. - * Refer to RTP: A Transport Protocol for Real-Time Applications ( RFC 3550 ) for more info. !Red! - * - * - * 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 _RTP__MESSAGE_H_ -#define _RTP__MESSAGE_H_ - -#include "../toxcore/network.h" -#include "toxrtp_helper.h" -#include "../toxcore/tox.h" -/* Defines */ - -#define _MAX_SEQU_NUM 65535 - -/* Minimum size */ -#define _MIN_HEADER_LENGTH 12 -#define _MIN_EXT_HEADER_LENGTH 4 - -/* End of defines */ - - -typedef struct rtp_dest_list_s { - tox_IP_Port _dest; - struct rtp_dest_list_s* next; - -} rtp_dest_list_t; - -typedef struct rtp_header_s { - uint8_t _flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ - uint8_t _marker_payload_t; /* Marker(1), PlayLoad Type(7) */ - uint16_t _sequence_number; /* Sequence Number */ - uint32_t _timestamp; /* Timestamp */ - uint32_t _ssrc; /* SSRC */ - uint32_t* _csrc; /* CSRC's table */ - - uint32_t _length; /* A little something for allocation */ - -} rtp_header_t; - -typedef struct rtp_ext_header_s { - uint16_t _ext_type; /* Extension profile */ - uint16_t _ext_len; /* Number of extensions */ - uint32_t* _hd_ext; /* Extension's table */ - - -} rtp_ext_header_t; - -typedef struct rtp_msg_s { - struct rtp_header_s* _header; - struct rtp_ext_header_s* _ext_header; - uint32_t _header_lenght; - - uint8_t* _data; - uint32_t _length; - tox_IP_Port _from; - - struct rtp_msg_s* _next; -} rtp_msg_t; - -/* Extracts the header from the payload starting at _from */ -rtp_header_t* rtp_extract_header ( const uint8_t* _payload, size_t _bytes ); -rtp_ext_header_t* rtp_extract_ext_header ( const uint8_t* _payload, size_t _bytes ); - - -uint8_t* rtp_add_header ( rtp_header_t* _header, uint8_t* _payload ); -uint8_t* rtp_add_extention_header ( rtp_ext_header_t* _header, uint8_t* _payload ); - -/* Gets the size of the header _header in bytes */ -size_t rtp_header_get_size ( const rtp_header_t* _header ); - -void rtp_header_print (const rtp_header_t* _header); - -/* Adding flags and settings */ -void rtp_header_add_flag_version ( rtp_header_t* _header, uint32_t value ); -void rtp_header_add_flag_padding ( rtp_header_t* _header, uint32_t value ); -void rtp_header_add_flag_extension ( rtp_header_t* _header, uint32_t value ); -void rtp_header_add_flag_CSRC_count ( rtp_header_t* _header, uint32_t value ); -void rtp_header_add_setting_marker ( rtp_header_t* _header, uint32_t value ); -void rtp_header_add_setting_payload ( rtp_header_t* _header, uint32_t value ); - - -/* Getting values from flags and settings */ -uint8_t rtp_header_get_flag_version ( const rtp_header_t* _header ); -uint8_t rtp_header_get_flag_padding ( const rtp_header_t* _header ); -uint8_t rtp_header_get_flag_extension ( const rtp_header_t* _header ); -uint8_t rtp_header_get_flag_CSRC_count ( const rtp_header_t* _header ); -uint8_t rtp_header_get_setting_marker ( const rtp_header_t* _header ); -uint8_t rtp_header_get_setting_payload_type ( const rtp_header_t* _header ); - -#endif /* _RTP__MESSAGE_H_ */