811 lines
27 KiB
C
Executable File
811 lines
27 KiB
C
Executable File
/*
|
|
* Copyright (C) 2010-2011 Mamadou Diop.
|
|
*
|
|
* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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>
|
|
*
|
|
|
|
*/
|
|
#include "tinysip/tsip_ssession.h"
|
|
|
|
#include "tinysip/tsip_action.h"
|
|
#include "tsip.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 *);
|
|
if(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_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;
|
|
}
|
|
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;
|
|
}
|
|
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, ...)
|
|
{
|
|
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;
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
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: {
|
|
/* 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_conditional_ringing = tmedia_defaults_get_conditional_ringing_enabled();
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
//=======
|
|
// 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;
|