c732d49e |
* Copyright (C) 2017, University of the Basque Country (UPV/EHU)
*
* Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
*
* This file is part of MCOP MCPTT Client
*
* This 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.
*
* This 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
*@file tmcptt_manager.c
* @brief MCPTT manager.
*
*/
#include "tinyrtp/trtp_manager.h"
#include "tinymcptt/tmcptt_manager.h"
#include "tinyrtp/rtp/trtp_rtp_packet.h"
#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
#include "tinyrtp/rtcp/trtp_rtcp_report_app.h"
#include "tinyrtp/rtcp/trtp_rtcp_session.h"
#include "tsk_string.h"
#include "tsk_memory.h"
#include "tsk_base64.h"
#include "tsk_md5.h"
#include "tsk_debug.h"
#include "tsk_timer.h"
#include <limits.h> /* INT_MAX */
#if !defined(TMCPTT_TRANSPORT_NAME)
# define TMCPTT_TRANSPORT_NAME "MCPTT Manager"
#endif
static tmcptt_manager_t* _tmcptt_manager_create(const char* local_ip)
{
tmcptt_manager_t* manager;
if((manager = (tmcptt_manager_t *)tsk_object_new(tmcptt_manager_def_t))){
manager->rtp_manager = trtp_manager_create(tsk_true, local_ip, tsk_false, tmedia_srtp_type_none, tmedia_srtp_mode_none);
manager->rtp_manager->use_rtcpmux = tsk_true;
manager->rtp_manager_mbms = trtp_manager_create(tsk_true, local_ip, tsk_false, tmedia_srtp_type_none, tmedia_srtp_mode_none);
manager->rtp_manager_mbms->use_rtcpmux = tsk_true;
manager->rtp_manager_mbms_floor = trtp_manager_create(tsk_true, local_ip, tsk_false, tmedia_srtp_type_none, tmedia_srtp_mode_none);
manager->rtp_manager_mbms_floor->use_rtcpmux = tsk_true;
}
return manager;
}
/*
static int tmcptt_manager_rtp_cb(const void* callback_data, const trtp_rtp_packet_t* packet)
{
int ret = 0;
tmcptt_manager_t* manager = (tmcptt_manager_t*)callback_data;
trtp_rtcp_packet_t* rtcp_packet = tsk_null;
tsk_size_t size;
char* data;
size = trtp_rtp_packet_guess_serialbuff_size(packet);
#if HAVE_CRT //Debug memory
data = (char*)tsk_malloc(size*sizeof(char));
#else
data = (char*)malloc(size*sizeof(char));
#endif //HAVE_CRT
size = trtp_rtp_packet_serialize_to(packet, data, size);
if(size <= 0){
TSK_FREE(data);
return -1;
}
rtcp_packet = (trtp_rtcp_packet_t*)trtp_rtcp_packet_deserialize(data, size);
if(manager->mcptt_callback.fun)
ret = manager->mcptt_callback.fun(manager->mcptt_callback.usrdata, rtcp_packet);
else{
TSK_DEBUG_ERROR("Undefined callback function");
ret = -1;
}
TSK_FREE(data);
return ret;
}
*/
/** Create MCPTT manager */
tmcptt_manager_t* tmcptt_manager_create(const char* local_ip)
{
tmcptt_manager_t* manager;
if((manager = _tmcptt_manager_create(local_ip))){
}
return manager;
}
/** Prepare MCPTT manager */
int tmcptt_manager_prepare(tmcptt_manager_t* self)
{
/*
const char *rtcp_local_ip = tsk_null;
tnet_port_t rtcp_local_port = 0;
tnet_socket_type_t socket_type;
uint8_t retry_count;
*/
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(self->rtp_manager->transport){
TSK_DEBUG_ERROR("MCPTT manager already prepared");
return -2;
}
/*
#define __retry_count_max 5
#define __retry_count_max_minus1 (__retry_count_max - 1)
retry_count = __retry_count_max;
socket_type = tnet_socket_type_udp_ipv4;
/* Creates local rtcp socket */
/*
while(retry_count--){
/* random number in the range 1024 to 65535 */
/*
static int counter = 0;
// first check => try to use port from latest active session if exist
tnet_port_t local_port = (retry_count == __retry_count_max_minus1 && (self->rtp_manager->port_range.start <= self->rtp_manager->rtcp.public_port && self->rtp_manager->rtcp.public_port <= self->rtp_manager->port_range.stop))
? self->rtp_manager->rtcp.public_port
: (((rand() ^ ++counter) % (self->rtp_manager->port_range.stop - self->rtp_manager->port_range.start)) + self->rtp_manager->port_range.start);
local_port = (local_port & 0xFFFE); /* turn to even number */
/* because failure will cause errors in the log, print a message to alert that there is
* nothing to worry about */
/*
TSK_DEBUG_INFO("MCPTT manager[Begin]: Trying to bind to random ports");
/* MCPTT */
/*
if(!(self->rtp_manager->transport = tnet_transport_create(self->rtp_manager->local_ip, local_port, socket_type, TMCPTT_TRANSPORT_NAME))){
TSK_DEBUG_ERROR("Failed to create MCPTT Transport");
return -3;
}
TSK_DEBUG_INFO("MCPTT manager[End]: Trying to bind to random ports");
break;
}// end-of-while(retry_count)
rtcp_local_ip = self->rtp_manager->transport->master->ip;
rtcp_local_port = self->rtp_manager->transport->master->port;
tsk_strupdate(&self->rtp_manager->rtcp.public_ip, rtcp_local_ip);
self->rtp_manager->rtcp.public_port = rtcp_local_port;
*/
trtp_manager_prepare(self->rtp_manager);
self->rtp_manager->transport->description = tsk_strdup("MCPTT Manager");
self->public_port = self->rtp_manager->rtp.public_port;
/*
if(self->rtp_manager->transport){
/* set callback function *//*
tnet_transport_set_callback(self->rtp_manager->transport, _tmcptt_transport_layer_cb, self);
}
*/
return 0;
}
/** Prepares the MBMS manager */
int tmcptt_mbms_manager_prepare(tmcptt_manager_t* self)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(self->rtp_manager_mbms->transport){
TSK_DEBUG_ERROR("MCPTT manager already prepared");
return -2;
}
//MCPTT MBMS
trtp_manager_prepare(self->rtp_manager_mbms);
if(self->rtp_manager_mbms){
self->rtp_manager_mbms->transport->description = tsk_strdup("MCPTT MBMS Manager");
self->public_port_mbms_manager = self->rtp_manager_mbms->rtp.public_port;
self->rtp_manager_mbms->use_rtcp = tsk_true; //trtp_manager_prepare sets these values to "false" if multicast
self->rtp_manager_mbms->use_rtcpmux = tsk_true;
}
return 0;
}
int tmcptt_mbms_floor_manager_prepare(tmcptt_manager_t* self)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(self->rtp_manager_mbms_floor->transport){
TSK_DEBUG_ERROR("MCPTT MBMS floor manager already prepared");
return -2;
}
//MCPTT MBMS floor ctrl
trtp_manager_prepare(self->rtp_manager_mbms_floor);
if(self->rtp_manager_mbms_floor){
self->rtp_manager_mbms_floor->transport->description = tsk_strdup("MCPTT MBMS Floor Manager");
self->rtp_manager_mbms_floor->use_rtcp = tsk_true; //trtp_manager_prepare sets these values to "false" if multicast
self->rtp_manager_mbms_floor->use_rtcpmux = tsk_true;
}
return 0;
}
/** Indicates whether the manager is already ready or not */
tsk_bool_t tmcptt_manager_is_ready(tmcptt_manager_t* self)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return tsk_false;
}
return (self->rtp_manager->transport != tsk_null);
}
/** Sets remote parameters for mcptt session */
int tmcptt_manager_set_mcptt_remote(tmcptt_manager_t* self, const char* remote_ip, tnet_port_t remote_port)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_strupdate(&self->rtp_manager->rtp.remote_ip, remote_ip);
self->rtp_manager->rtp.remote_port = remote_port;
return 0;
}
/** Sets remote parameters for mbms session */
int tmcptt_manager_set_mcptt_mbms_remote(tmcptt_manager_t* self, const char* remote_ip, tnet_port_t remote_port)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_strupdate(&self->rtp_manager_mbms->rtp.remote_ip, remote_ip);
self->rtp_manager_mbms->rtp.remote_port = remote_port;
return 0;
}
/** Sets remote parameters for MBMS floor control session */
int tmcptt_manager_set_mcptt_mbms_floor_remote(tmcptt_manager_t* self, const char* remote_ip, tnet_port_t remote_port)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_strupdate(&self->rtp_manager_mbms_floor->rtp.remote_ip, remote_ip);
self->rtp_manager_mbms_floor->rtp.remote_port = remote_port;
return 0;
}
/** Sets MCPTT callback */
int tmcptt_manager_set_mcptt_callback(tmcptt_manager_t* self, trtp_rtcp_cb_f fun, const void* usrdata)
{
if(!self || !self->rtp_manager){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
// self->mcptt_callback.fun = fun;
// self->mcptt_callback.usrdata = usrdata;
// return trtp_manager_set_rtp_callback(self->rtp_manager, tmcptt_manager_rtp_cb, self);
// return trtp_manager_set_rtp_callback(self->rtp_manager, fun, usrdata);
return trtp_manager_set_rtcp_callback(self->rtp_manager, fun, usrdata);
}
/** Sets MBMS callback */
int tmcptt_manager_set_mcptt_mbms_callback(tmcptt_manager_t* self, trtp_rtcp_cb_f fun, const void* usrdata)
{
if(!self || !self->rtp_manager_mbms){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
// self->mcptt_callback.fun = fun;
// self->mcptt_callback.usrdata = usrdata;
// return trtp_manager_set_rtp_callback(self->rtp_manager, tmcptt_manager_rtp_cb, self);
// return trtp_manager_set_rtp_callback(self->rtp_manager, fun, usrdata);
return trtp_manager_set_rtcp_callback(self->rtp_manager_mbms, fun, usrdata);
}
int tmcptt_manager_set_mcptt_mbms_floor_callback(tmcptt_manager_t* self, trtp_rtcp_cb_f fun, const void* usrdata)
{
if(!self || !self->rtp_manager_mbms_floor){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
// self->mcptt_callback.fun = fun;
// self->mcptt_callback.usrdata = usrdata;
// return trtp_manager_set_rtp_callback(self->rtp_manager, tmcptt_manager_rtp_cb, self);
// return trtp_manager_set_rtp_callback(self->rtp_manager, fun, usrdata);
return trtp_manager_set_rtcp_callback(self->rtp_manager_mbms_floor, fun, usrdata);
}
int tmcptt_manager_set_port_range(tmcptt_manager_t* self, uint16_t start, uint16_t stop)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
self->rtp_manager->port_range.start = start;
self->rtp_manager->port_range.stop = stop;
return 0;
}
int tmcptt_mbms_manager_set_port_range(tmcptt_manager_t* self, uint16_t start, uint16_t stop)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
self->rtp_manager_mbms->port_range.start = start;
self->rtp_manager_mbms->port_range.stop = stop;
return 0;
}
int tmcptt_mbms_floor_manager_set_port_range(tmcptt_manager_t* self, uint16_t start, uint16_t stop)
{
if(!self){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
self->rtp_manager_mbms_floor->port_range.start = start;
self->rtp_manager_mbms_floor->port_range.stop = stop;
return 0;
}
/** Starts the MCPTT manager */
int tmcptt_manager_start(tmcptt_manager_t* self)
{
int ret = 0;
// int rcv_buf = (int)tmedia_defaults_get_rtpbuff_size();
// int snd_buf = (int)tmedia_defaults_get_rtpbuff_size();
//
// if(!self){
// TSK_DEBUG_ERROR("Invalid parameter");
// return -1;
// }
//
// tsk_safeobj_lock(self);
//
// if (self->rtp_manager->is_started) {
// goto bail;
// }
//
// if(!self->rtp_manager->transport && (ret = tmcptt_manager_prepare(self))){
// TSK_DEBUG_ERROR("Failed to prepare MCPTT manager");
// goto bail;
// }
//
// if(!self->rtp_manager->transport || !self->rtp_manager->transport->master){
// TSK_DEBUG_ERROR("MCPTT manager not prepared");
// ret = -2;
// goto bail;
// }
//
// /* Flush buffers and re-enable sockets */
// if(self->rtp_manager->transport->master && self->rtp_manager->is_socket_disabled){
// static char buff[1024];
// tsk_size_t guard_count = 0;
//
// TSK_DEBUG_INFO("Start flushing MCPTT socket...");
// // Buffer should be empty ...but who knows?
// // rcv() should never block() as we are always using non-blocking sockets
// while ((ret = recv(self->rtp_manager->transport->master->fd, buff, sizeof(buff), 0)) > 0 && ++guard_count < 0xF0){
// TSK_DEBUG_INFO("Flushing MCPTT Buffer %d", ret);
// }
// TSK_DEBUG_INFO("End flushing MCPTT socket");
// }
//
// /* enlarge socket buffer */
// TSK_DEBUG_INFO("SO_RCVBUF = %d, SO_SNDBUF = %d", rcv_buf, snd_buf);
// if((ret = setsockopt(self->rtp_manager->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf)))){
// TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF, %d) has failed with error code %d", rcv_buf, ret);
// }
// if((ret = setsockopt(self->rtp_manager->transport->master->fd, SOL_SOCKET, SO_SNDBUF, (char*)&snd_buf, sizeof(snd_buf)))){
// TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_SNDBUF, %d) has failed with error code %d", snd_buf, ret);
// }
//
//
// // check remote IP address validity
// if((tsk_striequals(self->rtp_manager->rtcp.remote_ip, "0.0.0.0") || tsk_striequals(self->rtp_manager->rtcp.remote_ip, "::"))) { // most likely loopback testing
// tnet_ip_t source = {0};
// tsk_bool_t updated = tsk_false;
// if(self->rtp_manager->transport && self->rtp_manager->transport->master){
// updated = (tnet_getbestsource(self->rtp_manager->transport->master->ip, self->rtp_manager->transport->master->port, self->rtp_manager->transport->master->type, &source) == 0);
// }
// // Not allowed to send data to "0.0.0.0"
// TSK_DEBUG_INFO("MCPTT remote IP contains not allowed value ...changing to '%s'", updated ? source : "oops");
// if(updated){
// tsk_strupdate(&self->rtp_manager->rtcp.remote_ip, source);
// }
// }
// if((ret = tnet_sockaddr_init(self->rtp_manager->rtcp.remote_ip, self->rtp_manager->rtcp.remote_port, self->rtp_manager->transport->master->type, &self->rtp_manager->rtcp.remote_addr))){
// tnet_transport_shutdown(self->rtp_manager->transport);
// TSK_OBJECT_SAFE_FREE(self->rtp_manager->transport);
// TSK_DEBUG_ERROR("Invalid MCPTT host:port [%s:%u]", self->rtp_manager->rtcp.remote_ip, self->rtp_manager->rtcp.remote_port);
// goto bail;
// }
// TSK_DEBUG_INFO("rtcp.remote_ip=%s, rtcp.remote_port=%d, rtcp.local_fd=%d", self->rtp_manager->rtcp.remote_ip, self->rtp_manager->rtcp.remote_port, self->rtp_manager->transport->master->fd);
//
// /* add RTCP socket to the transport */
// if(self->rtp_manager->rtcp.local_socket){
// TSK_DEBUG_INFO("rtcp.local_ip=%s, rtcp.local_port=%d, rtcp.local_fd=%d", self->rtp_manager->rtcp.local_socket->ip, self->rtp_manager->rtcp.local_socket->port, self->rtp_manager->rtcp.local_socket->fd);
// if(ret == 0 && (ret = tnet_transport_add_socket(self->rtp_manager->transport, self->rtp_manager->rtcp.local_socket->fd, self->rtp_manager->rtcp.local_socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null))){
// TSK_DEBUG_ERROR("Failed to add RTCP socket");
// /* do not exit */
// }
// }
//
// /* create and start RTCP session */
// if(!self->rtp_manager->rtcp.session && ret == 0){
// self->rtp_manager->rtcp.session = trtp_rtcp_session_create_2(self->rtp_manager->ice_ctx, self->rtp_manager->rtp.ssrc.local, self->rtp_manager->rtcp.cname);
// }
//
// if (ret = tnet_transport_start(self->rtp_manager->transport)) {
// TSK_DEBUG_ERROR("Failed to start the RTP/RTCP transport");
// goto bail;
// }
//
// self->rtp_manager->is_started = tsk_true;
//
//bail:
//
// tsk_safeobj_unlock(self); |