mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
tox A/V: RTP/MSI implementation
This commit is contained in:
parent
1b971de651
commit
da727875ac
69
toxmsi/Makefile.inc
Normal file
69
toxmsi/Makefile.inc
Normal file
|
@ -0,0 +1,69 @@
|
|||
if BUILD_AV
|
||||
|
||||
lib_LTLIBRARIES += libtoxmsi.la
|
||||
|
||||
libtoxmsi_la_include_HEADERS = \
|
||||
../toxmsi/toxmsi.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/AV_codec.h \
|
||||
../toxmsi/AV_codec.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
|
62
toxmsi/phone.h
Normal file
62
toxmsi/phone.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#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 <assert.h>
|
||||
#include <pthread.h>
|
||||
#include "AV_codec.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_ */
|
835
toxmsi/toxmsi.c
Normal file
835
toxmsi/toxmsi.c
Normal file
|
@ -0,0 +1,835 @@
|
|||
|
||||
#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 <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
145
toxmsi/toxmsi.h
Normal file
145
toxmsi/toxmsi.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _MSI_IMPL_H_
|
||||
#define _MSI_IMPL_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/tox.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#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_ */
|
214
toxmsi/toxmsi_event.c
Normal file
214
toxmsi/toxmsi_event.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "toxmsi_event.h"
|
||||
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
46
toxmsi/toxmsi_event.h
Normal file
46
toxmsi/toxmsi_event.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef _MSI__EVENT_H_
|
||||
#define _MSI__EVENT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
|
||||
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_ */
|
181
toxmsi/toxmsi_header.c
Normal file
181
toxmsi/toxmsi_header.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxmsi_message.h"
|
||||
#include <string.h>
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
99
toxmsi/toxmsi_header.h
Normal file
99
toxmsi/toxmsi_header.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
#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_ */
|
267
toxmsi/toxmsi_message.c
Normal file
267
toxmsi/toxmsi_message.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxmsi_message.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../toxrtp/toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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)
|
||||
}
|
120
toxmsi/toxmsi_message.h
Normal file
120
toxmsi/toxmsi_message.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef _MSI_MESSAGE_H_
|
||||
#define _MSI_MESSAGE_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <inttypes.h>
|
||||
#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_ */
|
34
toxrtp/Makefile.inc
Normal file
34
toxrtp/Makefile.inc
Normal file
|
@ -0,0 +1,34 @@
|
|||
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
|
1
toxrtp/tests/Makefile.inc
Normal file
1
toxrtp/tests/Makefile.inc
Normal file
|
@ -0,0 +1 @@
|
|||
|
109
toxrtp/tests/test_bidirect.c
Normal file
109
toxrtp/tests/test_bidirect.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
#define _BSD_SOURCE
|
||||
|
||||
#include "../toxrtp.h"
|
||||
#include "../toxrtp_message.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utime.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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 */
|
316
toxrtp/tests/test_headers.c
Normal file
316
toxrtp/tests/test_headers.c
Normal file
|
@ -0,0 +1,316 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "test_helper.h"
|
||||
#include "../toxrtp.h"
|
||||
#include "../toxrtp_message.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utime.h>
|
||||
#include <assert.h>
|
||||
#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 */
|
83
toxrtp/tests/test_helper.c
Normal file
83
toxrtp/tests/test_helper.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "test_helper.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
61
toxrtp/tests/test_helper.h
Normal file
61
toxrtp/tests/test_helper.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
||||
|
||||
|
693
toxrtp/toxrtp.c
Normal file
693
toxrtp/toxrtp.c
Normal file
|
@ -0,0 +1,693 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp.h"
|
||||
#include "toxrtp_message.h"
|
||||
#include "toxrtp_helper.h"
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#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;
|
||||
}
|
188
toxrtp/toxrtp.h
Normal file
188
toxrtp/toxrtp.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RTP__IMPL_H_
|
||||
#define _RTP__IMPL_H_
|
||||
|
||||
#define RTP_VERSION 2
|
||||
#include <inttypes.h>
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
/* 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_ */
|
68
toxrtp/toxrtp_error.c
Normal file
68
toxrtp/toxrtp_error.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_error.h"
|
||||
#include "toxrtp_helper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
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 );
|
||||
}
|
25
toxrtp/toxrtp_error.h
Normal file
25
toxrtp/toxrtp_error.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#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_ */
|
32
toxrtp/toxrtp_error_id.h
Normal file
32
toxrtp/toxrtp_error_id.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#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_ */
|
209
toxrtp/toxrtp_helper.c
Normal file
209
toxrtp/toxrtp_helper.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_helper.h"
|
||||
#include "../toxcore/network.h"
|
||||
|
||||
#include <arpa/inet.h> /* Fixes implicit function warning. */
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WIN
|
||||
#include <windows.h>
|
||||
#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;
|
||||
}
|
77
toxrtp/toxrtp_helper.h
Normal file
77
toxrtp/toxrtp_helper.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RTP__HELPER_H_
|
||||
#define _RTP__HELPER_H_
|
||||
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* 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_ */
|
||||
|
||||
|
||||
|
||||
|
351
toxrtp/toxrtp_message.c
Normal file
351
toxrtp/toxrtp_message.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp_message.h"
|
||||
#include "toxrtp.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _USE_ERRORS
|
||||
#include "toxrtp_error_id.h"
|
||||
#endif /* _USE_ERRORS */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
111
toxrtp/toxrtp_message.h
Normal file
111
toxrtp/toxrtp_message.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
Loading…
Reference in New Issue
Block a user