/* 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;
}
/* */