From da727875ac954b13ecb16521d255499511bb7424 Mon Sep 17 00:00:00 2001 From: mannol Date: Sun, 13 Oct 2013 16:16:47 +0200 Subject: tox A/V: RTP/MSI implementation --- toxrtp/toxrtp_message.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 toxrtp/toxrtp_message.c (limited to 'toxrtp/toxrtp_message.c') diff --git a/toxrtp/toxrtp_message.c b/toxrtp/toxrtp_message.c new file mode 100644 index 00000000..e7f1f2c0 --- /dev/null +++ b/toxrtp/toxrtp_message.c @@ -0,0 +1,351 @@ +/* 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; +} + +/* */ + + -- cgit v1.2.3