doubango/tinySIP/src/tsip_ssession.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO 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.
 *
 * DOUBANGO 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 DOUBANGO.
 *
 */
 
 
 /**@file tsip_ssession.c
  * @brief SIP session.
  *
  * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
  *
 
  */
175b478c
 
 #include <tinysip.h>
 #include <tinysip/tsip_ssession.h>
c732d49e
 #include "tinysip/tsip_ssession.h"
 
 #include "tinysip/tsip_action.h"
 #include "tsip.h"
 #include "tinysip/tsip_uri.h"
 
 #include "tinysip/parsers/tsip_parser_uri.h"
 
 #include "tinysip/dialogs/tsip_dialog_layer.h"
 #include "tinysip/tsip_message.h"
 
 #include "tinymedia/tmedia_defaults.h"
 
 
 #include "tsk_debug.h"
 
 /**@defgroup tsip_session_group SIP sessions
 */
 
 /* internal function used to create session for server dialogs */
 tsip_ssession_handle_t* tsip_ssession_create_2(const tsip_stack_t* stack, const struct tsip_message_s* message)
 {
 	tsip_ssession_t* ss = tsk_null;
 
 	if(message){
 		char *from = tsk_null, *to = tsk_null;
 		
 		/* From: */
 		if(message->From && message->From->uri){ /* MUST be not null */
 			from = tsip_uri_tostring(message->From->uri, tsk_false, tsk_false);
 		}
 		/* To: */
 		if(message->To && message->To->uri){ /* MUST be not null */
 			to = tsip_uri_tostring(message->To->uri, tsk_false, tsk_false);
 		}
 		/* create the "server-side-session" */
 		if((ss = tsip_ssession_create((tsip_stack_handle_t*)stack, TSIP_SSESSION_SET_NULL()))){
 			tsip_ssession_set(ss, 
 				/* default values should be in conformance with the swig wrapper */
 				TSIP_SSESSION_SET_FROM_STR(from),
 				TSIP_SSESSION_SET_TO_STR(to),
 				TSIP_SSESSION_SET_NULL());
 		}
 
 		/* in all cases */
 		TSK_FREE(from);
 		TSK_FREE(to);
 	}
 	
 	/* as the it's a "server-side-session", you are not the owner
 	* The end-user should call tsip_ssession_have_ownership() to check whether he has the ownership.
 	* The end-user should also call tsip_ssession_take_ownership() to take the ownership. This will avoid the session to be deleted by the stack
 	* when the associated dialog ends. */
 	if(ss){
 		ss->owner = tsk_false;
 	}
 	
 	return ss;
 }
 
 int __tsip_ssession_set_To(tsip_ssession_t *self, const char* value)
 {	
 	tsip_uri_t* uri;
 	if(value && (uri = tsip_uri_parse(value, tsk_strlen(value)))){
 		TSK_OBJECT_SAFE_FREE(self->to);
 		self->to = uri;
 		return 0;
 	}
 	else{
 		TSK_DEBUG_ERROR("%s is invalid as 'To' header value", value);
 		return -1;
 	}
 }
 
 int __tsip_ssession_set_From(tsip_ssession_t *self, const char* value)
 {
 	tsip_uri_t* uri;
 	if(value && (uri = tsip_uri_parse(value, tsk_strlen(value)))){
 		TSK_OBJECT_SAFE_FREE(self->from);
 		self->from = uri;
 		return 0;
 	}
 	else{
 		TSK_DEBUG_ERROR("%s is invalid as 'From' header value", value);
 		return -1;
 	}
 }
 
 int __tsip_ssession_set(tsip_ssession_t *self, va_list *app)
 {
 	tsip_ssession_param_type_t sscurr;
 	tsip_msession_param_type_t mscurr;
 	tmedia_session_mgr_t* mgr = tsk_null;
 
 	int ret = 0;
 
 	if(!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 
 	while((sscurr = va_arg(*app, tsip_ssession_param_type_t)) != sstype_null){
 		switch(sscurr){
 			//=======
 			//	Sip
 			//=======
 			case sstype_header:
 			case sstype_caps:
 				{	/* (const char*)NAME_STR, (const char*)VALUE_STR */
 					const char* name = va_arg(*app, const char *);
 					const char* value = va_arg(*app, const char *);
 					
 					if(sscurr == sstype_header){
 						/* whether to SET or UNSET the header */
 						if(value == ((const char*)-1)){
 							tsk_params_remove_param(self->headers, name);
 							break;
 						}
 
 						/* From */
 						if(value && tsk_striequals(name, "From")){
 							if((ret = __tsip_ssession_set_From(self, value))){
 								goto bail;
 							}
 						}
 						/* To */
 						else if(value && tsk_striequals(name, "To")){
 							if((ret = __tsip_ssession_set_To(self, value))){
 								goto bail;
 							}
 						}
 						/* Expires */
 						else if(value && tsk_striequals(name, "Expires")){
 							/* should never happen ==> ...but who know? */
 						}
 						/* Any other */
 						else{
 							tsk_params_add_param(&self->headers, name, value);
 						}
 					}else if(sscurr == sstype_caps){
 						if(value == ((const char*)-1)){ /* UNSET */
 							tsk_params_remove_param(self->caps, name);
 						}
 						else{ /* SET */
 							tsk_params_add_param(&self->caps, name, value);
 						}
 					}
 					break;
 				}
 			case sstype_userdata:
 				{	/* (const void*)DATA_PTR */
 					self->userdata = va_arg(*app, const void *);
 					break;
 				}
 			case sstype_to_str:
 				{	/* (const char*)URI_STR */
 					if((ret = __tsip_ssession_set_To(self, va_arg(*app, const char *)))){
 						goto bail;
 					}
 					break;
 				}
 			case sstype_from_str:
 				{	/* (const char*)URI_STR*/
 					if((ret = __tsip_ssession_set_From(self, va_arg(*app, const char *)))){
 						goto bail;
 					}
 					break;
 				}
 			case sstype_to_obj:
 				{	/* (const tsip_uri_t*)URI_OBJ */
 					const tsip_uri_t* URI_OBJ = va_arg(*app, const tsip_uri_t *);
 					//URI_OBJ is the obj that has datas from URI. ej:user_name=example
 					if(URI_OBJ){
 						//Free the obj self from  intro now obj whit URI_OBJ
 						TSK_OBJECT_SAFE_FREE(self->to);
 						self->to = tsk_object_ref((void*)URI_OBJ);
 					}
 					break;
 				}
 			case sstype_from_obj:
 				{	/* (const char*)URI_OBJ*/
 					const tsip_uri_t* URI_OBJ = va_arg(*app, const tsip_uri_t *);
 					if(URI_OBJ){
 						TSK_OBJECT_SAFE_FREE(self->from);
 						self->from = tsk_object_ref((void*)URI_OBJ);
 					}
 					break;
 				}
 			case sstype_nocontact:
 				{	/* (tsk_bool_t)ENABLED_BOOL */
 					self->no_contact = va_arg(*app, tsk_bool_t);
 					break;
 				}
 			case sstype_expires:
 				{	/* (unsigned)VALUE_UINT */
 					self->expires = (((int64_t)va_arg(*app, unsigned)) * 1000) /* milliseconds */;
 					break;
 				}
 			case sstype_silent_hangup:
 				{	/* sstype_silent_hangup, (tsk_bool_t)ENABLED_BOOL */
 					self->silent_hangup = va_arg(*app, tsk_bool_t);
 					break;
 				}
 			case sstype_sigcomp_id:
 				{ /* (const char*)COMPARTMENT_ID_STR */
 					const char* COMPARTMENT_ID_STR = va_arg(*app, const char*);
 					if(COMPARTMENT_ID_STR == (const char*)-1){
 						TSK_FREE(self->sigcomp_id);
 					}
 					else{
 						tsk_strupdate(&self->sigcomp_id, COMPARTMENT_ID_STR);
 					}
 					break;
 				}
 			case sstype_auth_ha1:
 				{ /* (const char*)AUTH_HA1_STR */
 					const char* AUTH_HA1_STR = va_arg(*app, const char*);
 					tsk_strupdate(&self->auth_ha1, AUTH_HA1_STR);
 					break;
 				}
 			case sstype_auth_impi:
 				{ /* (const char*)AUTH_IMPI_STR */
 					const char* AUTH_IMPI_STR = va_arg(*app, const char*);
 					tsk_strupdate(&self->auth_impi, AUTH_IMPI_STR);
 					break;
 				}
 			case sstype_mcptt_mbms_start_manager:
 				{
 					self->pttMCPTT.mbms.isStartMbmsManager = va_arg(*app, tsk_bool_t);
 					break;
 				}
 			case sstype_parent_id:
 				{	/* ((tsip_ssession_id_t)PARENT_ID_SSID) */
 					self->id_parent = va_arg(*app, tsip_ssession_id_t);
 					break;
 				}
 			case sstype_ws_src:
 				{	/* (const char*)SRC_HOST_STR, (int32_t)SRC_PORT_INT, (const char*)SRC_PROTO_STR */
 					const char* SRC_HOST_STR = va_arg(*app, const char*); 
 					int32_t SRC_PORT_INT = va_arg(*app, int32_t);  
 					const char* SRC_PROTO_STR = va_arg(*app, const char*); 
 					tsk_strupdate(&self->ws.src.host, SRC_HOST_STR);
 					tsk_itoa(SRC_PORT_INT, &self->ws.src.port);
 					tsk_strupdate(&self->ws.src.proto, SRC_PROTO_STR);
 					break;
 				}
 	
 			case sstype_media:
 				{
 					//=========
 					//	Media
 					//=========
                     if (!mgr) {
                         mgr = tsip_session_get_mediamgr(self);
                     }
 					while((mscurr = va_arg(*app, tsip_msession_param_type_t)) != mstype_null){
 						switch(mscurr){
 							case mstype_set_profile:
 								// (tmedia_profile_t)PROFILE_ENUM
 								self->media.profile = va_arg(*app, tmedia_profile_t);
 								break;
 							case mstype_set_srtp_mode:
 								// (tmedia_srtp_mode_t)SRTP_MODE_ENUM
 								self->media.srtp_mode = va_arg(*app, tmedia_srtp_mode_t);
 								break;
 							case mstype_set_avpf_mode:
 								// (tmedia_mode_t)MEDIA_MODE_ENUM
 								self->media.avpf_mode = va_arg(*app, tmedia_mode_t);
 								break;
 							case mstype_set_100rel: self->media.enable_100rel = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_ice: self->media.enable_ice = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_ice_stun: self->media.enable_icestun = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_ice_turn: self->media.enable_iceturn = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_rtcp: self->media.enable_rtcp = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_rtcpmux: self->media.enable_rtcpmux = va_arg(*app, tsk_bool_t); break;
 							case mstype_set_qos:
 								{	/* (tmedia_qos_stype_t)TYPE_ENUM, (tmedia_qos_strength_t)STRENGTH_ENUM */
 									self->media.qos.type = va_arg(*app, tmedia_qos_stype_t);
 									self->media.qos.strength = va_arg(*app, tmedia_qos_strength_t);
 									break;
 								}
 							case mstype_unset_qos:
 								{	/*  */
 									self->media.qos.type = tmedia_qos_stype_none;
 									self->media.qos.strength = tmedia_qos_strength_none;
 									break;
 								}
 							case mstype_set_timers:
 								{ /* (unsigned)TIMEOUT_UINT, (const char*)REFRESHER_STR */
 									/* set values */
 									self->media.timers.timeout = va_arg(*app, unsigned);
 									tsk_strupdate(&self->media.timers.refresher, va_arg(*app, const char*));
 									break;
 								}
 							case mstype_unset_timers:
 								{ /*  */
 									/* unset values */
 									self->media.timers.timeout = 0;
 									TSK_FREE(self->media.timers.refresher);
 									break;
 								}
 							case mstype_set_codecs:
 								{/* (signed)CODECS_INT */
 									self->media.codecs = va_arg(*app, signed);
 									if(mgr){ // apply now
 										tmedia_session_mgr_set_codecs_supported(mgr, self->media.codecs);
 									}
 									break;
 								}
 							case mstype_set_bypass_encoding:
 								{/* (tsk_bool_t)ENABLED_BOOL */
 									self->media.bypass_encoding = va_arg(*app, tsk_bool_t);
 									break;
 								}
 							case mstype_set_bypass_decoding:
 								{/* (tsk_bool_t)ENABLED_BOOL */
 									self->media.bypass_decoding = va_arg(*app, tsk_bool_t);
 									break;
 								}
 							case mstype_set_rtp_ssrc:
 								{/* (tmedia_type_t)MEDIA_ENUM, (uint32_t)SSRC_UINT */
 									tmedia_type_t MEDIA_ENUM = va_arg(*app, tmedia_type_t);
 									uint32_t SSRC_UINT = va_arg(*app, uint32_t);
 									switch(MEDIA_ENUM){
 										case tmedia_audio: self->media.rtp.ssrc.audio = SSRC_UINT; break;
 										case tmedia_video: self->media.rtp.ssrc.video = SSRC_UINT; break;
                                         default: break;
 									}
 									break;
 								}
 							case mstype_set_msrp_cb:
 								{	/* (tmedia_session_msrp_cb_f)TMEDIA_SESSION_MSRP_CB_F */
 									self->media.msrp.callback = va_arg(*app, tmedia_session_msrp_cb_f);
 									break;
 								}
 								//MCPTT
 							case mstype_set_mcptt_cb:
 								{	/* (tmedia_session_mcptt_cb_f)TMEDIA_SESSION_MCPTT_CB_F */
 									self->media.mcptt.callback = va_arg(*app, tmedia_session_mcptt_cb_f);
 									break;
 								}
175b478c
 								//MCPTT AFFILIATION
c732d49e
 							case mstype_set_mcptt_affiliation_cb:
 								{	/* (tmedia_session_mcptt_affiliation_cb_f)TMEDIA_SESSION_MCPTT_AFFILIATION_CB_F */
 									self->media.mcptt_affiliation.callback = va_arg(*app, tmedia_session_mcptt_affiliation_cb_f);
 									break;
 								}
 							case mstype_set_stun_server:
 								{	/* (const char*)HOSTNAME, (uint16_t)PORT */
 									const char* HOSTNAME = va_arg(*app, const char*);
 									uint16_t PORT = tsk_va_arg_u16(*app);
 									tsk_strupdate(&self->media.stun.hostname, HOSTNAME);
 									self->media.stun.port = PORT;
 									break;
 								}
 							case mstype_set_stun_cred:
 								{	/* (const char*)USERNAME, (const char*)PASSWORD */
 									const char* USERNAME = va_arg(*app, const char*);
 									const char* PASSWORD = va_arg(*app, const char*);
 									tsk_strupdate(&self->media.stun.username, USERNAME);
 									tsk_strupdate(&self->media.stun.password, PASSWORD);
 									break;
 								}
 							case mstype_set_video_fps:
 								{/* (signed)FPS_INT */
 									self->media.video_fps = va_arg(*app, signed);
 									break;
 								}
 							case mstype_set_video_bw_up:
 								{/* (signed)BW_INT */
 									self->media.video_bw_up = va_arg(*app, signed);
 									break;
 								}
 							case mstype_set_video_bw_down:
 								{/* (signed)BW_INT */
 									self->media.video_bw_down = va_arg(*app, signed);
 									break;
 								}
 							case mstype_set_video_prefsize:
 								{/* (tmedia_pref_video_size_t)PREFSIZE_ENUM */
 									self->media.video_pref_size = va_arg(*app, tmedia_pref_video_size_t);
 									break;
 								}
 							case mstype_set_poc_qoe:
 								{	
 									self->media.poc_qoe.profile = va_arg(*app, tmedia_poc_qoe_profile_t);
 									self->media.poc_qoe.strength = va_arg(*app, tmedia_poc_qoe_profile_strength_t);
 									break;
 								}
 							default:{
 								/* va_list will be unsafe => exit */
 								TSK_DEBUG_ERROR("%d NOT a valid MEDIA pname", mscurr);
 								goto bail; }
 						} /* switch */
 					} /* while */
 					
 					break;
 				} /* case */
 
 			default:{
 				/* va_list will be unsafe => exit */
 				TSK_DEBUG_ERROR("%d NOT a valid SIP pname", sscurr);
 				goto bail; }
 				
 		} /* switch */
 	} /* while */
 
 bail:
 	TSK_OBJECT_SAFE_FREE(mgr);
 
 	return ret;
 }
 
 
 tsip_ssession_handle_t* tsip_ssession_create(tsip_stack_handle_t *stack, ...)
 {
175b478c
     TSK_DEBUG_INFO("tsip_ssession_create");
c732d49e
 	tsip_ssession_t* ss = tsk_null;
 	va_list ap;
 	tsip_stack_t* _stack = stack;
 
 	if(!_stack){
 		TSK_DEBUG_ERROR("Invalid Parameter.");
 		goto bail;
 	}
 
 	if(!(ss = tsk_object_new(tsip_ssession_def_t, stack))){
 		TSK_DEBUG_ERROR("Failed to create new SIP Session.");
 		return tsk_null;
 	}
 
 	va_start(ap, stack);
 	if(__tsip_ssession_set(ss, &ap)){
 		TSK_DEBUG_ERROR("Failed to set user's parameters.");
 		TSK_OBJECT_SAFE_FREE(ss);
 		va_end(ap);
 		goto bail;
 	}
 	va_end(ap);
 
 	/* from */
 	if(!ss->from && _stack->identity.impu){
 		ss->from = tsip_uri_clone(_stack->identity.impu, tsk_false, tsk_false);
 	}
 	/* to */
 	/* To value will be set by the dialog (whether to use as Request-URI). */
 
 bail:
 	return ss;
 }
 
 int tsip_ssession_set(tsip_ssession_handle_t *self, ...)
 {
 	if(self){
 		int ret;
 		va_list ap;
 
 		tsip_ssession_t *ss = self;
 
 		if(ss->id == TSIP_SSESSION_INVALID_ID){
 			return -2;
 		}
 		
 		va_start(ap, self);
 		ret = __tsip_ssession_set(ss, &ap);
 		va_end(ap);
 		return ret;
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 }
 
 tsip_ssession_id_t tsip_ssession_get_id(const tsip_ssession_handle_t *self)
 {
 	if(self){
 		const tsip_ssession_t *ss = self;
 		if(ss && ss!=tsk_null){
 			return ss->id;
 		}
 	}
 	return TSIP_SSESSION_INVALID_ID;
 }
 
 tsip_ssession_id_t tsip_ssession_get_id_parent(const tsip_ssession_handle_t *self)
 {
 	if(self){
 		const tsip_ssession_t *ss = self;
 		return ss->id_parent;
 	}
 	return TSIP_SSESSION_INVALID_ID;
 }
 
 int tsip_ssession_take_ownership(tsip_ssession_handle_t *self)
 {
 	if(self){
 		tsip_ssession_t *ss = self;
 		if(!ss->owner){
 			ss->owner = tsk_true;
 			/* before: only the dialog had a reference to the SIP session */
 			ss = tsk_object_ref(ss);
 			/* after: both the end-user and the dialog have their references */
 			return 0;
 		}
 		return -2;
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return -1;
 	}
 }
 
 tsk_bool_t tsip_ssession_have_ownership(const tsip_ssession_handle_t *self)
 {
 	if(self){
 		const tsip_ssession_t *ss = self;
 		return ss->owner;
 	}
 	return tsk_false;
 }
 
 int tsip_ssession_respond(const tsip_ssession_handle_t *self, short status, const char* phrase, const void* payload, tsk_size_t size, const struct tsip_message_s* request, ...)
 {
 	tsip_response_t *response = tsk_null;
 	tsip_dialog_t* dialog = tsk_null;
 	const tsip_ssession_t *ss = self;
 	int ret = -1;
 
 	if(!ss || !request){
 		goto bail;
 	}
 	
 	if(!(dialog = tsip_dialog_layer_find_by_ss(ss->stack->layer_dialog, ss))){
 		goto bail;
 	}
 
 	if(!(response = tsip_dialog_response_new(TSIP_DIALOG(self), status, phrase, request))){
 		goto bail;
 	}
 
 	if(payload && size){
 		if((ret = tsip_message_add_content(response, tsk_null, payload, size))){
 			goto bail;
 		}
 	}
 	ret = tsip_dialog_response_send(TSIP_DIALOG(self), response);
 
 bail:
 	TSK_OBJECT_SAFE_FREE(response);
 	TSK_OBJECT_SAFE_FREE(dialog);
 
 	return ret;
 }
 
 const void* tsip_ssession_get_userdata(const tsip_ssession_handle_t *self)
 {
 	const tsip_ssession_t* ss = (const tsip_ssession_t*)self;
 	if(ss){
 		return ss->userdata;
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return tsk_null;
 	}
 }
 
 tmedia_type_t tsip_ssession_get_mediatype(const tsip_ssession_handle_t *self)
 {
 	if(self){
 		return ((const tsip_ssession_t*)self)->media.type;
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return tmedia_none;
 	}
 }
 
 #include "tinysip/dialogs/tsip_dialog_invite.h"
 tmedia_session_mgr_t* tsip_session_get_mediamgr(const tsip_ssession_handle_t *self)
 {
 	tmedia_session_mgr_t* mgr = tsk_null;
175b478c
     TSK_DEBUG_INFO("tsip_session_get_mediamgr");
c732d49e
 	if(self){
 		const tsip_ssession_t *ss = self;
 		tsip_dialog_t* dialog;
 		if((dialog = tsip_dialog_layer_find_by_ss(ss->stack->layer_dialog, self))){
             if(dialog->type == tsip_dialog_INVITE){
                 mgr = tsk_object_ref(TSIP_DIALOG_INVITE(dialog)->msession_mgr);
             }
 			tsk_object_unref(dialog);
 		}
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 	}
 
 	return mgr;
 }
 
 const tsip_stack_handle_t* tsip_ssession_get_stack(const tsip_ssession_handle_t *self)
 {
 	if(self){
 		return ((const tsip_ssession_t*)self)->stack;
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return tsk_null;
 	}
 }
 
 tmedia_codec_id_t tsip_ssession_get_codecs_neg(tsip_ssession_handle_t *self)
 {
 	int32_t codecs_neg = (int32_t)tmedia_codec_id_none;
 	if(self){
 		tmedia_session_mgr_t* mgr = tsip_session_get_mediamgr(self);
 		if(mgr){
 			(tmedia_session_mgr_get(mgr,
 				TMEDIA_SESSION_GET_INT32(mgr->type, "codecs-negotiated", &codecs_neg),
 				TMEDIA_SESSION_GET_NULL()));
 			TSK_OBJECT_SAFE_FREE(mgr);
 		}
 	}
 	return (tmedia_codec_id_t)codecs_neg;
 }
 
175b478c
 //MCPTT
c732d49e
 const char* tsip_ssession_get_ptt_mcptt_group_identity(tsip_ssession_handle_t *self)
 {
175b478c
 
     tsip_ssession_t* ss = (tsip_ssession_t*)self;
     char* member = tsk_null;
     TSK_DEBUG_INFO("Init tsip_ssession_get_ptt_mcptt_group_identity");
     if(ss && ss->pttMCPTT.ptt_group_uri!=tsk_null)
     {
         TSK_DEBUG_INFO("Parameter for call uri %s",ss->pttMCPTT.ptt_group_uri);
 #if HAVE_CRT //Debug memory
         member = (char*)calloc(strlen((ss->pttMCPTT.ptt_group_uri))+1, sizeof(char));
 
 #else
         member = (char*)tsk_calloc(strlen((ss->pttMCPTT.ptt_group_uri))+1, sizeof(char));
 
 #endif //HAVE_CRT
         tsk_strupdate(&member, ss->pttMCPTT.ptt_group_uri);
         return member;
     }
     else
         return "(null)";
 
c732d49e
 }
 
 
 
 int tsip_ssession_get_ptt_mcptt_group_members(tsip_ssession_handle_t *self)
 {
 	tsip_ssession_t* ss = (tsip_ssession_t*)self;
 	tsk_size_t count = 0;
 	if(ss)
 		count = tsk_list_count(ss->pttMCPTT.ptt_group_members, tsk_null, tsk_null);
 	
 	return (int)count;
 }
 
 const char* tsip_ssession_get_ptt_mcptt_group_member_at_position(tsip_ssession_handle_t *self, int pos)
 {
 	tsip_ssession_t* ss = (tsip_ssession_t*)self;
 	char* member_id = tsk_null;
 	if(ss && ss->pttMCPTT.ptt_group_members != tsk_null)
 	{
 		char* member = tsk_null;
 		const tsk_string_t* member_str_obj = tsk_null;
 		member_str_obj = (const tsk_string_t*)tsk_list_find_object_by_pred_at_index(ss->pttMCPTT.ptt_group_members, tsk_null, tsk_null, pos);
 		if(member_str_obj != tsk_null && member_str_obj->value != tsk_null)
 		{
 			#if HAVE_CRT //Debug memory
 			member = (char*)calloc(strlen(member_str_obj->value) + 1, sizeof(char));
 		
 	#else
 			member = (char*)tsk_calloc(strlen(member_str_obj->value) + 1, sizeof(char));
 		
 	#endif //HAVE_CRT
 			tsk_strupdate(&member, member_str_obj->value);
 		}
 		return member;
 	}
 	else
 		return tsk_null;
 }
 
175b478c
 int tsip_ssession_get_ptt_mcptt_emergence_resource_priority(tsip_ssession_handle_t *self)
 {
 	tsip_ssession_t* ss = (tsip_ssession_t*)self;
 	tsk_size_t count = 0;
 	if(ss)
 		count = ss->pttMCPTT.emergency.resource_priority_int;
 	
 	return (int)count;
 }
 
 const char* tsip_ssession_get_ptt_mcptt_emergence_resource_priority_string(tsip_ssession_handle_t *self)
 {
 	tsip_ssession_t* ss = (tsip_ssession_t*)self;
 	char* group_id = tsk_null;
 	if(ss)
 	{
 		tsk_strupdate(&group_id, ss->pttMCPTT.emergency.resource_priority_string);
 		return (const char*)group_id;
 	}
 	else
 		return tsk_null;
 }
c732d49e
 
 //
 char* tsip_ssession_get_party_uri(tsip_ssession_handle_t *self)
 {
 	
 	
 	tsip_ssession_t* ss = (tsip_ssession_t*)self;
 	char* member_id = tsk_null;
 	char* member = tsk_null;
 	TSK_DEBUG_INFO("Init tsip_ssession_get_party_uri");
 	if(ss && ss->pttMCPTT.ptt_caller_uri!=tsk_null)
 	{
 		TSK_DEBUG_INFO("Parameter for call uri %s",ss->pttMCPTT.ptt_caller_uri);
 		#if HAVE_CRT //Debug memory
 		member = (char*)calloc(strlen((ss->pttMCPTT.ptt_caller_uri))+1, sizeof(char));
175b478c
 		#else
c732d49e
 		member = (char*)tsk_calloc(strlen((ss->pttMCPTT.ptt_caller_uri))+1, sizeof(char));
175b478c
 		#endif //HAVE_CRT
c732d49e
 		tsk_strupdate(&member, ss->pttMCPTT.ptt_caller_uri);
 		return member;
 	}
 	else
 		return "(null)";
 		
 }
 
 
 
 
 
 
 
 int tsip_ssession_handle(const tsip_ssession_t *self, const struct tsip_action_s* action)
 {
 	int ret = -1;
 
 	if(self && self->stack && action){
 		tsip_dialog_t *dialog;
 				
 		if((dialog = tsip_dialog_layer_find_by_ss(self->stack->layer_dialog, self))){
 			switch(action->type){
 				case tsip_atype_hangup:
175b478c
 					TSK_DEBUG_INFO("tsip_atype_hangup");
c732d49e
 					{	/* hang-up is an special case (==> hangup/cancel/nothing) */
 						ret = tsip_dialog_hangup(dialog, action);
 						break;
 					}
 				default:
 					{	/* All other cases */
 						ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action);
 						break;
 					}
 			}
 			/* unref */
 			tsk_object_unref(dialog);
 		}
 		else{
 			TSK_DEBUG_ERROR("Failed to find dialog with this opid [%lld]", self->id);
 		}
 	}
 	else{
 		TSK_DEBUG_ERROR("Invalid parameter");
 	}
 
 	return ret;
 }
 
 
 
 
 
 //========================================================
 //	SIP Session object definition
 //
 static tsk_object_t* tsip_ssession_ctor(tsk_object_t * self, va_list * app)
 {
 	tsip_ssession_t *ss = self;
 	static tsip_ssession_id_t unique_id = 0;
 	if(ss){
 		ss->stack = va_arg(*app, const tsip_stack_t*);
 		ss->caps = tsk_list_create();
 		ss->headers = tsk_list_create();
 		
 		/* unique identifier */
 		ss->id = ++unique_id;
 		// default: you are the owner
 		ss->owner = tsk_true;
 		// default expires value
 		ss->expires = TSIP_SSESSION_EXPIRES_DEFAULT;
 		// default parentid: not parent -> no pending transfer
 		ss->id_parent = TSIP_SSESSION_INVALID_ID;
 		// default SigComp compId (will be updated by session_set())
 		if (ss->stack->sigcomp.handle) {
 			ss->sigcomp_id = tsk_strdup(tsip_sigcomp_handler_fixme_getcompid(ss->stack->sigcomp.handle));
 		}
 		// default media values
 		ss->media.profile = tmedia_defaults_get_profile();
 		ss->media.srtp_mode = tmedia_defaults_get_srtp_mode();
 		ss->media.avpf_mode = tmedia_defaults_get_avpf_mode();
 		ss->media.enable_100rel = tmedia_defaults_get_100rel_enabled();
 		ss->media.enable_ice = tmedia_defaults_get_ice_enabled();
 		ss->media.enable_icestun = tmedia_defaults_get_icestun_enabled();
 		ss->media.enable_iceturn = tmedia_defaults_get_iceturn_enabled();
 		ss->media.enable_rtcp = tmedia_defaults_get_rtcp_enabled();
 		ss->media.enable_rtcpmux = tmedia_defaults_get_rtcpmux_enabled();
 		ss->media.type = tmedia_none;
 		ss->media.qos.type = tmedia_qos_stype_none;
 		ss->media.qos.strength = tmedia_qos_strength_none;
 		ss->media.timers.refresher = tsk_strdup(tmedia_defaults_get_inv_session_refresher());
 		ss->media.timers.timeout = tmedia_defaults_get_inv_session_expires();
 		ss->media.codecs = tmedia_codec_id_all;
 		ss->media.bypass_encoding = tmedia_defaults_get_bypass_encoding();
 		ss->media.bypass_decoding = tmedia_defaults_get_bypass_decoding();
 		ss->media.video_fps = tmedia_defaults_get_video_fps();
 		ss->media.video_bw_down = tmedia_defaults_get_bandwidth_video_download_max();
 		ss->media.video_bw_up = tmedia_defaults_get_bandwidth_video_upload_max();
 		ss->media.video_pref_size = tmedia_defaults_get_pref_video_size();
 		{
 			const char *stun_hostname, *stun_username, *stun_password;
 			uint16_t stun_port;
 			if(tmedia_defaults_get_stun_server(&stun_hostname, &stun_port) == 0){
 				ss->media.stun.hostname = tsk_strdup(stun_hostname);
 				ss->media.stun.port = stun_port;
 			}
 			if(tmedia_defaults_get_stun_cred(&stun_username, &stun_password) == 0){
 				ss->media.stun.username = tsk_strdup(stun_username);
 				ss->media.stun.password = tsk_strdup(stun_password);
 			}
 		}
 		ss->media.poc_qoe.profile = tmedia_defaults_get_poc_qoe_profile();
 		ss->media.poc_qoe.strength = tmedia_defaults_get_poc_qoe_profile_strength();
175b478c
 		//MCPTT Z�rate
c732d49e
 		ss->pttMCPTT.ptt_caller_uri = tsk_null;
175b478c
 		ss->pttMCPTT.answer_mode_auto = tsk_false;
c732d49e
 		ss->pttMCPTT.ptt_group_uri = tsk_null;
 		ss->pttMCPTT.ptt_group_members = tsk_null;
175b478c
 		//MCPTT emergency
c732d49e
 		ss->pttMCPTT.emergency.resource_priority_string=tsk_null;
 		ss->pttMCPTT.emergency.resource_priority_int=-1;
 		ss->pttMCPTT.mbms.port_manager = -1;
 		ss->pttMCPTT.mbms.addr_multicast = tsk_null;
 		ss->pttMCPTT.mbms.is_rtcp_mux=tsk_false;
 		ss->pttMCPTT.mbms.sdp_ro=tsk_null;
 		ss->pttMCPTT.mbms.tmgi=tsk_null;
175b478c
 
c732d49e
 
 		/* add the session to the stack */
 		if(ss->stack){
 			tsk_list_push_back_data(ss->stack->ssessions, (void**)&ss);
 		}
 	}
 
 	return self;
 }
 
 static tsk_object_t* tsip_ssession_dtor(tsk_object_t * self)
 { 
 	tsip_ssession_t *ss = self;
 	if(ss){
 		/* remove from the stack */
 		if(ss->stack){
 			tsk_list_remove_item_by_data(ss->stack->ssessions, ss);
 		}
175b478c
 		//MCPTT Zarate
 		ss->pttMCPTT.answer_mode_auto=tsk_false;
c732d49e
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.ptt_caller_uri);
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.ptt_group_uri);
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.ptt_group_members);
175b478c
 		//MCPTT Emergency Zarate
c732d49e
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.emergency.resource_priority_string);
 		ss->pttMCPTT.emergency.resource_priority_int=-1;
 		/*
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.multicastMbms.addr_multicast);
 		ss->pttMCPTT.multicastMbms.port_manager = -1;
 		ss->pttMCPTT.multicastMbms.is_rtcp_mux=tsk_false;
 		TSK_OBJECT_SAFE_FREE(ss->pttMCPTT.multicastMbms.sdp_ro);
 		*/
 
 
 		//=======
 		// SIP
 		//=======
 		TSK_OBJECT_SAFE_FREE(ss->caps);
 		TSK_OBJECT_SAFE_FREE(ss->headers);
 
 		TSK_OBJECT_SAFE_FREE(ss->from);
 		TSK_OBJECT_SAFE_FREE(ss->to);
 
 		TSK_FREE(ss->sigcomp_id);
 		TSK_FREE(ss->auth_ha1);
 		TSK_FREE(ss->auth_impi);
 
 		//=======
 		// Media
 		//=======
 		TSK_FREE(ss->media.timers.refresher);
 		TSK_FREE(ss->media.stun.username);
 		TSK_FREE(ss->media.stun.password);
 		TSK_FREE(ss->media.stun.hostname);
 
 		//=======
 		// WebSocket
 		//=======
 		TSK_FREE(ss->ws.src.host);
 		TSK_FREE(ss->ws.src.proto);
 
 		TSK_DEBUG_INFO("*** SIP Session destroyed ***");
 	}
 	return self;
 }
 
 static int tsip_ssession_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
 {
 	const tsip_ssession_t *ss1 = obj1;
 	const tsip_ssession_t *ss2 = obj2;
 
 	if(ss1 && ss2){
 		return (int)(ss1->id-ss2->id);
 	}
 	return -1;
 }
 
 static const tsk_object_def_t tsip_ssession_def_s = 
 {
 	sizeof(tsip_ssession_t),
 	tsip_ssession_ctor, 
 	tsip_ssession_dtor,
 	tsip_ssession_cmp, 
 };
 const tsk_object_def_t *tsip_ssession_def_t = &tsip_ssession_def_s;