From 65d320e31daa4709bb48b7f2a52c269dde0927e9 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 25 Jan 2014 01:32:33 +0100 Subject: Done with encryption and core adaptations. --- toxav/toxrtp.c | 878 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100755 toxav/toxrtp.c (limited to 'toxav/toxrtp.c') 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 -- cgit v1.2.3