diff options
Diffstat (limited to 'tinySIP/src/dialogs/tsip_dialog_invite.server.c')
-rwxr-xr-x | tinySIP/src/dialogs/tsip_dialog_invite.server.c | 1092 |
1 files changed, 546 insertions, 546 deletions
diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.server.c b/tinySIP/src/dialogs/tsip_dialog_invite.server.c index 2a7a37c..9082ca2 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.server.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.server.c @@ -2,19 +2,19 @@ * 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 publishd 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. * @@ -78,145 +78,145 @@ static int s0000_Any_2_Any_X_timer100rel(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_bad_extension(tsip_dialog_invite_t* self, tsip_message_t* message) { - const tsip_header_Require_t* requireHdr; - const tsk_list_item_t* item; - tsk_size_t i, j; - - /* Check if we support all extensions */ - for(i = 0; (requireHdr = (const tsip_header_Require_t*)tsip_message_get_headerAt(message, tsip_htype_Require, i)); i++){ - tsk_bool_t bad_extension = tsk_false; - const tsk_string_t* option = tsk_null; - tsk_list_foreach(item, requireHdr->options){ - option = item->data; - bad_extension = tsk_true; - for(j = 0; option && j<sizeof(supported_options)/sizeof(const char*); j++){ - if(tsk_striequals(option->value, supported_options[j])){ - bad_extension = tsk_false; - break; - } - } - if(bad_extension){ - break; - } - } - if(bad_extension && option){ - send_UNSUPPORTED(self, message, option->value); - return tsk_true; - } - } - - - return tsk_false; + const tsip_header_Require_t* requireHdr; + const tsk_list_item_t* item; + tsk_size_t i, j; + + /* Check if we support all extensions */ + for(i = 0; (requireHdr = (const tsip_header_Require_t*)tsip_message_get_headerAt(message, tsip_htype_Require, i)); i++) { + tsk_bool_t bad_extension = tsk_false; + const tsk_string_t* option = tsk_null; + tsk_list_foreach(item, requireHdr->options) { + option = item->data; + bad_extension = tsk_true; + for(j = 0; option && j<sizeof(supported_options)/sizeof(const char*); j++) { + if(tsk_striequals(option->value, supported_options[j])) { + bad_extension = tsk_false; + break; + } + } + if(bad_extension) { + break; + } + } + if(bad_extension && option) { + send_UNSUPPORTED(self, message, option->value); + return tsk_true; + } + } + + + return tsk_false; } static tsk_bool_t _fsm_cond_bad_content(tsip_dialog_invite_t* self, tsip_message_t* message) { - int ret; - const tsdp_message_t* sdp_lo; - tsk_bool_t bodiless_INVITE = (TSIP_DIALOG(self)->state == tsip_initial && !TSIP_MESSAGE_HAS_CONTENT(message)); // Initial Bodiless INVITE - - /* Check remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, message))){ - ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return tsk_true; - } - /* generate local offer and check it's validity */ - if(self->msession_mgr && (sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr))){ - /* check that we have at least one valid session (Only if no bodiless initial INVITE) */ - if(!bodiless_INVITE && !tmedia_session_mgr_has_active_session(self->msession_mgr)){ - ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"No common codecs\""); - return tsk_true; - } - // media type could change if there are zombies (medias with port equal to zero) - TSIP_DIALOG_GET_SS(self)->media.type = self->msession_mgr->type; - } - else{ - ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return tsk_true; - } - - return tsk_false; + int ret; + const tsdp_message_t* sdp_lo; + tsk_bool_t bodiless_INVITE = (TSIP_DIALOG(self)->state == tsip_initial && !TSIP_MESSAGE_HAS_CONTENT(message)); // Initial Bodiless INVITE + + /* Check remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, message))) { + ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return tsk_true; + } + /* generate local offer and check it's validity */ + if(self->msession_mgr && (sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr))) { + /* check that we have at least one valid session (Only if no bodiless initial INVITE) */ + if(!bodiless_INVITE && !tmedia_session_mgr_has_active_session(self->msession_mgr)) { + ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"No common codecs\""); + return tsk_true; + } + // media type could change if there are zombies (medias with port equal to zero) + TSIP_DIALOG_GET_SS(self)->media.type = self->msession_mgr->type; + } + else { + ret = send_ERROR(self, message, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return tsk_true; + } + + return tsk_false; } static tsk_bool_t _fsm_cond_toosmall(tsip_dialog_invite_t* self, tsip_message_t* message) { - if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout && (tsip_message_supported(message, "timer") || tsip_message_required(message, "timer"))){ - const tsip_header_Session_Expires_t* Session_Expires; - if((Session_Expires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))){ - if(Session_Expires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE){ - self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; - send_RESPONSE(self, message, 422, "Session Interval Too Small", tsk_false); - return tsk_true; - } - else{ - const tsip_header_Min_SE_t* Min_SE; - self->stimers.timer.timeout = Session_Expires->delta_seconds; - tsk_strupdate(&self->stimers.refresher, Session_Expires->refresher_uas ? "uas" : "uac"); - self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uas"); - if((Min_SE = (const tsip_header_Min_SE_t*)tsip_message_get_header(message, tsip_htype_Min_SE))){ - self->stimers.minse = Min_SE->delta_seconds; - } - } - } - } - return tsk_false; + if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout && (tsip_message_supported(message, "timer") || tsip_message_required(message, "timer"))) { + const tsip_header_Session_Expires_t* Session_Expires; + if((Session_Expires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))) { + if(Session_Expires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE) { + self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; + send_RESPONSE(self, message, 422, "Session Interval Too Small", tsk_false); + return tsk_true; + } + else { + const tsip_header_Min_SE_t* Min_SE; + self->stimers.timer.timeout = Session_Expires->delta_seconds; + tsk_strupdate(&self->stimers.refresher, Session_Expires->refresher_uas ? "uas" : "uac"); + self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uas"); + if((Min_SE = (const tsip_header_Min_SE_t*)tsip_message_get_header(message, tsip_htype_Min_SE))) { + self->stimers.minse = Min_SE->delta_seconds; + } + } + } + } + return tsk_false; } // 100rel && (QoS or ICE) static tsk_bool_t _fsm_cond_use_early_media(tsip_dialog_invite_t* self, tsip_message_t* message) { - if((tsip_message_supported(message, "100rel") && self->supported._100rel) || tsip_message_required(message, "100rel")){ - if((tsip_message_supported(message, "precondition") && self->supported.precondition) || tsip_message_required(message, "precondition")){ - return tsk_true; - } - } + if((tsip_message_supported(message, "100rel") && self->supported._100rel) || tsip_message_required(message, "100rel")) { + if((tsip_message_supported(message, "precondition") && self->supported.precondition) || tsip_message_required(message, "precondition")) { + return tsk_true; + } + } #if 0 - if(tsip_dialog_invite_ice_is_enabled(self)){ - return tsk_true; - } + if(tsip_dialog_invite_ice_is_enabled(self)) { + return tsk_true; + } #endif - return tsk_false; + return tsk_false; } static tsk_bool_t _fsm_cond_prack_match(tsip_dialog_invite_t* self, tsip_message_t* message) { - const tsip_header_RAck_t* RAck; - - if(!self->last_o1xxrel){ - return tsk_false; - } - - if((RAck = (const tsip_header_RAck_t*)tsip_message_get_header(message, tsip_htype_RAck))){ - if((RAck->seq == self->rseq) && - (tsk_striequals(RAck->method, self->last_o1xxrel->CSeq->method)) && - (RAck->cseq == self->last_o1xxrel->CSeq->seq)){ - self->rseq++; - return tsk_true; - } - else{ - TSK_DEBUG_WARN("Failed to match PRACK request"); - } - } - - return tsk_false; + const tsip_header_RAck_t* RAck; + + if(!self->last_o1xxrel) { + return tsk_false; + } + + if((RAck = (const tsip_header_RAck_t*)tsip_message_get_header(message, tsip_htype_RAck))) { + if((RAck->seq == self->rseq) && + (tsk_striequals(RAck->method, self->last_o1xxrel->CSeq->method)) && + (RAck->cseq == self->last_o1xxrel->CSeq->seq)) { + self->rseq++; + return tsk_true; + } + else { + TSK_DEBUG_WARN("Failed to match PRACK request"); + } + } + + return tsk_false; } static tsk_bool_t _fsm_cond_negociates_preconditions(tsip_dialog_invite_t* self, tsip_message_t* rPRACK) { - //tsip_message_supported(self->last_iInvite, "precondition") || tsip_message_required(self->last_iInvite, "precondition") - if(tsip_message_required(self->last_iInvite, "precondition") || (self->msession_mgr && self->msession_mgr->qos.strength == tmedia_qos_strength_mandatory)){ - return tsk_true; - } - return tsk_false; + //tsip_message_supported(self->last_iInvite, "precondition") || tsip_message_required(self->last_iInvite, "precondition") + if(tsip_message_required(self->last_iInvite, "precondition") || (self->msession_mgr && self->msession_mgr->qos.strength == tmedia_qos_strength_mandatory)) { + return tsk_true; + } + return tsk_false; } static tsk_bool_t _fsm_cond_cannotresume(tsip_dialog_invite_t* self, tsip_message_t* rUPDATE) { - if(!tsip_dialog_invite_process_ro(self, rUPDATE)){ - return !tmedia_session_mgr_canresume(self->msession_mgr); - } - else{ - return tsk_false; - } + if(!tsip_dialog_invite_process_ro(self, rUPDATE)) { + return !tmedia_session_mgr_canresume(self->msession_mgr); + } + else { + return tsk_false; + } } static tsk_bool_t _fsm_cond_initial_iack_pending(tsip_dialog_invite_t* self, tsip_message_t* rACK) @@ -229,64 +229,64 @@ static tsk_bool_t _fsm_cond_initial_iack_pending(tsip_dialog_invite_t* self, tsi /* Init FSM */ int tsip_dialog_invite_server_init(tsip_dialog_invite_t *self) { - return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (Bad Extendion) -> Terminated - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_bad_extension, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iINVITE, "s0000_Started_2_Terminated_X_iINVITE"), - // Started -> (Bad content) -> Terminated - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_bad_content, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iINVITE, "s0000_Started_2_Terminated_X_iINVITE"), - // Started -> (Session Interval Too Small) -> Started - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_toosmall, _fsm_state_Started, s0000_Started_2_Started_X_iINVITE, "s0000_Started_2_Started_X_iINVITE"), - // Started -> (100rel && (QoS or ICE)) -> InProgress - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_use_early_media, _fsm_state_InProgress, s0000_Started_2_InProgress_X_iINVITE, "s0000_Started_2_InProgress_X_iINVITE"), - // Started -> (non-100rel and non-QoS, referred to as "basic") -> Ringing - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_iINVITE, _fsm_state_Ringing, s0000_Started_2_Ringing_X_iINVITE, "s0000_Started_2_Ringing_X_iINVITE"), - - - /*======================= - * === InProgress === - */ - // InProgress ->(iPRACK with QoS) -> InProgress - TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iPRACK, _fsm_cond_negociates_preconditions, _fsm_state_InProgress, s0000_InProgress_2_InProgress_X_iPRACK, "s0000_InProgress_2_InProgress_X_iPRACK"), - // InProgress ->(iPRACK without QoS) -> Ringing - TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iPRACK, _fsm_cond_prack_match, _fsm_state_Ringing, s0000_InProgress_2_Ringing_X_iPRACK, "s0000_InProgress_2_Ringing_X_iPRACK"), - // InProgress ->(iUPDATE but cannot resume) -> InProgress - TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iUPDATE, _fsm_cond_cannotresume, _fsm_state_InProgress, s0000_InProgress_2_InProgress_X_iUPDATE, "s0000_InProgress_2_InProgress_X_iUPDATE"), - // InProgress ->(iUPDATE can resume) -> Ringing - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_iUPDATE, _fsm_state_Ringing, s0000_InProgress_2_Ringing_X_iUPDATE, "s0000_InProgress_2_Ringing_X_iUPDATE"), - // InProgress ->(iCANCEL) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_iCANCEL, _fsm_state_Terminated, s0000_Inprogress_2_Terminated_X_iCANCEL, "s0000_Inprogress_2_Terminated_X_iCANCEL"), - - - /*======================= - * === Ringing === - */ - // Ringing -> (iPRACK) -> Ringing - TSK_FSM_ADD(_fsm_state_Ringing, _fsm_action_iPRACK, _fsm_cond_prack_match, _fsm_state_Ringing, s0000_Ringing_2_Ringing_X_iPRACK, "s0000_Ringing_2_Ringing_X_iPRACK"), - // Ringing -> (oAccept) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_accept, _fsm_state_Connected, s0000_Ringing_2_Connected_X_Accept, "s0000_Ringing_2_Connected_X_Accept"), - // Ringing -> (oReject) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_reject, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_Reject, "s0000_Ringing_2_Terminated_X_Reject"), - // Ringing ->(iCANCEL) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_iCANCEL, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_iCANCEL, "s0000_Ringing_2_Terminated_X_iCANCEL"), - - /*======================= - * === FRESH CONNECTED === - */ - // Fresh Connected [ACK is pending] ->(iCANCEL) -> Terminated - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iCANCEL, _fsm_cond_initial_iack_pending, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_iCANCEL, "s0000_FreshConnected_2_Terminated_X_iCANCEL"), - - /*======================= - * === ANY === - */ - // Any ->(timer100rel) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_timer100rel, tsk_fsm_state_any, s0000_Any_2_Any_X_timer100rel, "s0000_Any_2_Any_X_timer100rel"), - - - TSK_FSM_ADD_NULL()); + return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (Bad Extendion) -> Terminated + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_bad_extension, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iINVITE, "s0000_Started_2_Terminated_X_iINVITE"), + // Started -> (Bad content) -> Terminated + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_bad_content, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iINVITE, "s0000_Started_2_Terminated_X_iINVITE"), + // Started -> (Session Interval Too Small) -> Started + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_toosmall, _fsm_state_Started, s0000_Started_2_Started_X_iINVITE, "s0000_Started_2_Started_X_iINVITE"), + // Started -> (100rel && (QoS or ICE)) -> InProgress + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iINVITE, _fsm_cond_use_early_media, _fsm_state_InProgress, s0000_Started_2_InProgress_X_iINVITE, "s0000_Started_2_InProgress_X_iINVITE"), + // Started -> (non-100rel and non-QoS, referred to as "basic") -> Ringing + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_iINVITE, _fsm_state_Ringing, s0000_Started_2_Ringing_X_iINVITE, "s0000_Started_2_Ringing_X_iINVITE"), + + + /*======================= + * === InProgress === + */ + // InProgress ->(iPRACK with QoS) -> InProgress + TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iPRACK, _fsm_cond_negociates_preconditions, _fsm_state_InProgress, s0000_InProgress_2_InProgress_X_iPRACK, "s0000_InProgress_2_InProgress_X_iPRACK"), + // InProgress ->(iPRACK without QoS) -> Ringing + TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iPRACK, _fsm_cond_prack_match, _fsm_state_Ringing, s0000_InProgress_2_Ringing_X_iPRACK, "s0000_InProgress_2_Ringing_X_iPRACK"), + // InProgress ->(iUPDATE but cannot resume) -> InProgress + TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_iUPDATE, _fsm_cond_cannotresume, _fsm_state_InProgress, s0000_InProgress_2_InProgress_X_iUPDATE, "s0000_InProgress_2_InProgress_X_iUPDATE"), + // InProgress ->(iUPDATE can resume) -> Ringing + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_iUPDATE, _fsm_state_Ringing, s0000_InProgress_2_Ringing_X_iUPDATE, "s0000_InProgress_2_Ringing_X_iUPDATE"), + // InProgress ->(iCANCEL) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_iCANCEL, _fsm_state_Terminated, s0000_Inprogress_2_Terminated_X_iCANCEL, "s0000_Inprogress_2_Terminated_X_iCANCEL"), + + + /*======================= + * === Ringing === + */ + // Ringing -> (iPRACK) -> Ringing + TSK_FSM_ADD(_fsm_state_Ringing, _fsm_action_iPRACK, _fsm_cond_prack_match, _fsm_state_Ringing, s0000_Ringing_2_Ringing_X_iPRACK, "s0000_Ringing_2_Ringing_X_iPRACK"), + // Ringing -> (oAccept) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_accept, _fsm_state_Connected, s0000_Ringing_2_Connected_X_Accept, "s0000_Ringing_2_Connected_X_Accept"), + // Ringing -> (oReject) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_reject, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_Reject, "s0000_Ringing_2_Terminated_X_Reject"), + // Ringing ->(iCANCEL) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Ringing, _fsm_action_iCANCEL, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_iCANCEL, "s0000_Ringing_2_Terminated_X_iCANCEL"), + + /*======================= + * === FRESH CONNECTED === + */ + // Fresh Connected [ACK is pending] ->(iCANCEL) -> Terminated + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iCANCEL, _fsm_cond_initial_iack_pending, _fsm_state_Terminated, s0000_Ringing_2_Terminated_X_iCANCEL, "s0000_FreshConnected_2_Terminated_X_iCANCEL"), + + /*======================= + * === ANY === + */ + // Any ->(timer100rel) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_timer100rel, tsk_fsm_state_any, s0000_Any_2_Any_X_timer100rel, "s0000_Any_2_Any_X_timer100rel"), + + + TSK_FSM_ADD_NULL()); } //-------------------------------------------------------- @@ -297,467 +297,467 @@ int tsip_dialog_invite_server_init(tsip_dialog_invite_t *self) /* Started -> (Failure) -> Terminated */ int s0000_Started_2_Terminated_X_iINVITE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - /* tsip_request_t *request = va_arg(*app, tsip_request_t *); */ + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + /* tsip_request_t *request = va_arg(*app, tsip_request_t *); */ - /* We are not the client */ - self->is_client = tsk_false; + /* We are not the client */ + self->is_client = tsk_false; - return 0; + return 0; } /* Started -> (Too Small) -> Started */ int s0000_Started_2_Started_X_iINVITE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - /* We are not the client */ - self->is_client = tsk_false; + /* We are not the client */ + self->is_client = tsk_false; - return 0; + return 0; } /* Started -> (non-100rel and non-QoS, referred to as "basic") -> Ringing */ int s0000_Started_2_Ringing_X_iINVITE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - const tsip_header_Session_Expires_t* hdr_SessionExpires; - - /* we are not the client */ - self->is_client = tsk_false; - - /* update last INVITE */ - TSK_OBJECT_SAFE_FREE(self->last_iInvite); - self->last_iInvite = tsk_object_ref(request); - - // add "require:100rel" tag if the incoming INVITE contains "100rel" tag in "supported" header - if(self->last_iInvite && (tsip_message_supported(self->last_iInvite, "100rel") || tsip_message_required(self->last_iInvite, "100rel")) && self->supported._100rel){ - self->required._100rel = tsk_true; - } - - // add "require:timer" tag if incoming INVITE contains "timer" tag in "supported" header and session timers is enabled - if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout){ - if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(request, tsip_htype_Session_Expires))){ - // "hdr_SessionExpires->delta_seconds" smallnest already checked - self->stimers.timer.timeout = hdr_SessionExpires->delta_seconds; - tsk_strupdate(&self->stimers.refresher, hdr_SessionExpires->refresher_uas ? "uas" : "uac"); - self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uas"); - self->required.timer = tsk_true; - } - } - - /* update state */ - tsip_dialog_update_2(TSIP_DIALOG(self), request); - - /* send Ringing */ - /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ - send_RESPONSE(self, request, 180, "Ringing", tsk_false); - } - - /* alert the user (session) */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, - tsip_event_code_dialog_request_incoming, "Incoming Call", request); - - return 0; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + const tsip_header_Session_Expires_t* hdr_SessionExpires; + + /* we are not the client */ + self->is_client = tsk_false; + + /* update last INVITE */ + TSK_OBJECT_SAFE_FREE(self->last_iInvite); + self->last_iInvite = tsk_object_ref(request); + + // add "require:100rel" tag if the incoming INVITE contains "100rel" tag in "supported" header + if(self->last_iInvite && (tsip_message_supported(self->last_iInvite, "100rel") || tsip_message_required(self->last_iInvite, "100rel")) && self->supported._100rel) { + self->required._100rel = tsk_true; + } + + // add "require:timer" tag if incoming INVITE contains "timer" tag in "supported" header and session timers is enabled + if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout) { + if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(request, tsip_htype_Session_Expires))) { + // "hdr_SessionExpires->delta_seconds" smallnest already checked + self->stimers.timer.timeout = hdr_SessionExpires->delta_seconds; + tsk_strupdate(&self->stimers.refresher, hdr_SessionExpires->refresher_uas ? "uas" : "uac"); + self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uas"); + self->required.timer = tsk_true; + } + } + + /* update state */ + tsip_dialog_update_2(TSIP_DIALOG(self), request); + + /* send Ringing */ + /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ + send_RESPONSE(self, request, 180, "Ringing", tsk_false); + } + + /* alert the user (session) */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, + tsip_event_code_dialog_request_incoming, "Incoming Call", request); + + return 0; } /* Started -> (QoS (preconditions)) -> InProgress */ int s0000_Started_2_InProgress_X_iINVITE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - - /* We are not the client */ - self->is_client = tsk_false; - - /* update last INVITE */ - TSK_OBJECT_SAFE_FREE(self->last_iInvite); - self->last_iInvite = tsk_object_ref(request); - - /* Update state */ - tsip_dialog_update_2(TSIP_DIALOG(self), request); - - /* Send In Progress - RFC 3262 - 3 UAS Behavior - - The provisional response to be sent reliably is constructed by the - UAS core according to the procedures of Section 8.2.6 of RFC 3261. - In addition, it MUST contain a Require header field containing the - option tag 100rel, and MUST include an RSeq header field. The value - of the header field for the first reliable provisional response in a - transaction MUST be between 1 and 2**31 - 1. - */ - self->rseq = (rand() ^ rand()) % (0x00000001 << 31); - self->required._100rel = tsk_true; - self->required.precondition = (tsip_message_supported(self->last_iInvite, "precondition") || tsip_message_required(self->last_iInvite, "precondition")); - send_RESPONSE(self, request, 183, "Session in Progress", tsk_true); - - return 0; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + + /* We are not the client */ + self->is_client = tsk_false; + + /* update last INVITE */ + TSK_OBJECT_SAFE_FREE(self->last_iInvite); + self->last_iInvite = tsk_object_ref(request); + + /* Update state */ + tsip_dialog_update_2(TSIP_DIALOG(self), request); + + /* Send In Progress + RFC 3262 - 3 UAS Behavior + + The provisional response to be sent reliably is constructed by the + UAS core according to the procedures of Section 8.2.6 of RFC 3261. + In addition, it MUST contain a Require header field containing the + option tag 100rel, and MUST include an RSeq header field. The value + of the header field for the first reliable provisional response in a + transaction MUST be between 1 and 2**31 - 1. + */ + self->rseq = (rand() ^ rand()) % (0x00000001 << 31); + self->required._100rel = tsk_true; + self->required.precondition = (tsip_message_supported(self->last_iInvite, "precondition") || tsip_message_required(self->last_iInvite, "precondition")); + send_RESPONSE(self, request, 183, "Session in Progress", tsk_true); + + return 0; } /* InProgress ->(iPRACK with QoS) -> InProgress */ int s0000_InProgress_2_InProgress_X_iPRACK(va_list *app) { - int ret; - - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - - /* Cancel 100rel timer */ - TSIP_DIALOG_TIMER_CANCEL(100rel); - - /* In all cases: Send 2xx PRACK */ - if(!(ret = send_RESPONSE(self, request, 200, "OK", tsk_false))){ - ++self->rseq; - } - - /* - 1. Alice sends an initial INVITE without offer - 2. Bob's answer is sent in the first reliable provisional response, in this case it's a 1xx INVITE response - 3. Alice's answer is sent in the PRACK response - */ - if(!self->msession_mgr->sdp.ro){ - if(TSIP_MESSAGE_HAS_CONTENT(request)){ - if((ret = tsip_dialog_invite_process_ro(self, request))){ - /* Send Error and break the FSM */ - ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return -4; - } - } - else{ - /* 488 INVITE */ - ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Offer expected in the PRACK\""); - return -3; - } - } - - return ret; + int ret; + + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + + /* Cancel 100rel timer */ + TSIP_DIALOG_TIMER_CANCEL(100rel); + + /* In all cases: Send 2xx PRACK */ + if(!(ret = send_RESPONSE(self, request, 200, "OK", tsk_false))) { + ++self->rseq; + } + + /* + 1. Alice sends an initial INVITE without offer + 2. Bob's answer is sent in the first reliable provisional response, in this case it's a 1xx INVITE response + 3. Alice's answer is sent in the PRACK response + */ + if(!self->msession_mgr->sdp.ro) { + if(TSIP_MESSAGE_HAS_CONTENT(request)) { + if((ret = tsip_dialog_invite_process_ro(self, request))) { + /* Send Error and break the FSM */ + ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return -4; + } + } + else { + /* 488 INVITE */ + ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Offer expected in the PRACK\""); + return -3; + } + } + + return ret; } /* InProgress ->(iPRACK without QoS) -> Ringing */ int s0000_InProgress_2_Ringing_X_iPRACK(va_list *app) { - int ret; - - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - - /* Cancel 100rel timer */ - TSIP_DIALOG_TIMER_CANCEL(100rel); - - /* In all cases: Send 2xx PRACK */ - if(!(ret = send_RESPONSE(self, request, 200, "OK", tsk_false))){ - ++self->rseq; - } - - /* - 1. Alice sends an initial INVITE without offer - 2. Bob's answer is sent in the first reliable provisional response, in this case it's a 1xx INVITE response - 3. Alice's answer is sent in the PRACK response - */ - if(self->msession_mgr && !self->msession_mgr->sdp.ro){ - if(TSIP_MESSAGE_HAS_CONTENT(request)){ - if((ret = tsip_dialog_invite_process_ro(self, request))){ - /* Send Error and break the FSM */ - ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return -4; - } - } - else{ - /* 488 INVITE */ - ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Offer expected in the PRACK\""); - return -3; - } - } - - /* Send Ringing */ - /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ - ret = send_RESPONSE(self, self->last_iInvite, 180, "Ringing", tsk_false); - } - - /* Alert the user (session) */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, - tsip_event_code_dialog_request_incoming, "Incoming Call", request); - - return ret; + int ret; + + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + + /* Cancel 100rel timer */ + TSIP_DIALOG_TIMER_CANCEL(100rel); + + /* In all cases: Send 2xx PRACK */ + if(!(ret = send_RESPONSE(self, request, 200, "OK", tsk_false))) { + ++self->rseq; + } + + /* + 1. Alice sends an initial INVITE without offer + 2. Bob's answer is sent in the first reliable provisional response, in this case it's a 1xx INVITE response + 3. Alice's answer is sent in the PRACK response + */ + if(self->msession_mgr && !self->msession_mgr->sdp.ro) { + if(TSIP_MESSAGE_HAS_CONTENT(request)) { + if((ret = tsip_dialog_invite_process_ro(self, request))) { + /* Send Error and break the FSM */ + ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return -4; + } + } + else { + /* 488 INVITE */ + ret = send_ERROR(self, self->last_iInvite, 488, "Not Acceptable", "SIP; cause=488; text=\"Offer expected in the PRACK\""); + return -3; + } + } + + /* Send Ringing */ + /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ + ret = send_RESPONSE(self, self->last_iInvite, 180, "Ringing", tsk_false); + } + + /* Alert the user (session) */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, + tsip_event_code_dialog_request_incoming, "Incoming Call", request); + + return ret; } /* InProgress ->(iUPDATE but cannot resume) -> InProgress */ int s0000_InProgress_2_InProgress_X_iUPDATE(va_list *app) { - int ret; - - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - - if((ret = tsip_dialog_invite_process_ro(self, request))){ - /* Send Error and break the FSM */ - ret = send_ERROR(self, request, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return -4; - } - else{ - // force SDP in 200 OK even if the request has the same SDP version - tsk_bool_t force_sdp = TSIP_MESSAGE_HAS_CONTENT(request); - ret = send_RESPONSE(self, request, 200, "OK", - (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); - } - - return ret; + int ret; + + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + + if((ret = tsip_dialog_invite_process_ro(self, request))) { + /* Send Error and break the FSM */ + ret = send_ERROR(self, request, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return -4; + } + else { + // force SDP in 200 OK even if the request has the same SDP version + tsk_bool_t force_sdp = TSIP_MESSAGE_HAS_CONTENT(request); + ret = send_RESPONSE(self, request, 200, "OK", + (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); + } + + return ret; } /* InProgress ->(iUPDATE can resume) -> Ringing */ int s0000_InProgress_2_Ringing_X_iUPDATE(va_list *app) { - int ret; - - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); - tsk_bool_t force_sdp; - - if((ret = tsip_dialog_invite_process_ro(self, request))){ - /* Send Error and break the FSM */ - ret = send_ERROR(self, request, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); - return -4; - } - - /* Send 200 UPDATE */ - // force SDP in 200 OK even if the request has the same SDP version - force_sdp = TSIP_MESSAGE_HAS_CONTENT(request); - ret = send_RESPONSE(self, request, 200, "OK", - (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); - - /* Send Ringing */ - /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ - ret = send_RESPONSE(self, self->last_iInvite, 180, "Ringing", tsk_false); - } - - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, - tsip_event_code_dialog_request_incoming, "Incoming Call", request); - - return ret; + int ret; + + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); + tsk_bool_t force_sdp; + + if((ret = tsip_dialog_invite_process_ro(self, request))) { + /* Send Error and break the FSM */ + ret = send_ERROR(self, request, 488, "Not Acceptable", "SIP; cause=488; text=\"Bad content\""); + return -4; + } + + /* Send 200 UPDATE */ + // force SDP in 200 OK even if the request has the same SDP version + force_sdp = TSIP_MESSAGE_HAS_CONTENT(request); + ret = send_RESPONSE(self, request, 200, "OK", + (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); + + /* Send Ringing */ + /*if(TSIP_DIALOG_GET_STACK(self)->network.mode != tsip_stack_mode_webrtc2sip)*/{ + ret = send_RESPONSE(self, self->last_iInvite, 180, "Ringing", tsk_false); + } + + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_newcall, + tsip_event_code_dialog_request_incoming, "Incoming Call", request); + + return ret; } /* InProgress ->(iCANCEL) -> Terminated */ int s0000_Inprogress_2_Terminated_X_iCANCEL(va_list *app) { - tsip_response_t* response; - int ret = -1; + tsip_response_t* response; + int ret = -1; - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); - /* Send 2xx for the CANCEL (Direct to Transport layer beacause CANCEL is a special case) */ - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))){ - ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, response); - TSK_OBJECT_SAFE_FREE(response); - } + /* Send 2xx for the CANCEL (Direct to Transport layer beacause CANCEL is a special case) */ + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))) { + ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, response); + TSK_OBJECT_SAFE_FREE(response); + } - /* Send Request Cancelled */ - ret = send_ERROR(self, self->last_iInvite, 487, "Request Cancelled", "SIP; cause=487; text=\"Request Cancelled\""); + /* Send Request Cancelled */ + ret = send_ERROR(self, self->last_iInvite, 487, "Request Cancelled", "SIP; cause=487; text=\"Request Cancelled\""); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Cancelled", tsip_event_code_dialog_terminated); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Cancelled", tsip_event_code_dialog_terminated); - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - return ret; + return ret; } /* Ringing -> (iPRACK) -> Ringing */ int s0000_Ringing_2_Ringing_X_iPRACK(va_list *app) { - int ret; + int ret; - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); - if(!self->last_iInvite){ - /* silently ignore */ - return 0; - } + if(!self->last_iInvite) { + /* silently ignore */ + return 0; + } - /* Cancel 100rel timer */ - TSIP_DIALOG_TIMER_CANCEL(100rel); + /* Cancel 100rel timer */ + TSIP_DIALOG_TIMER_CANCEL(100rel); - /* Send 2xx PRACK */ - ret = send_RESPONSE(self, request, 200, "OK", tsk_false); + /* Send 2xx PRACK */ + ret = send_RESPONSE(self, request, 200, "OK", tsk_false); - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - return ret; + return ret; } /* Ringing -> (oAccept) -> Connected */ int s0000_Ringing_2_Connected_X_Accept(va_list *app) { - int ret; + int ret; + + tsip_dialog_invite_t *self; + const tsip_action_t* action; + tsk_bool_t mediaType_changed; - tsip_dialog_invite_t *self; - const tsip_action_t* action; - tsk_bool_t mediaType_changed; + self = va_arg(*app, tsip_dialog_invite_t *); + va_arg(*app, const tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); - self = va_arg(*app, tsip_dialog_invite_t *); - va_arg(*app, const tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); + /* Determine whether the remote party support UPDATE */ + self->support_update = tsip_message_allowed(self->last_iInvite, "UPDATE"); - /* Determine whether the remote party support UPDATE */ - self->support_update = tsip_message_allowed(self->last_iInvite, "UPDATE"); + /* Get Media type from the action */ + mediaType_changed = (TSIP_DIALOG_GET_SS(self)->media.type != action->media.type && action->media.type != tmedia_none); + if(self->msession_mgr && mediaType_changed) { + ret = tmedia_session_mgr_set_media_type(self->msession_mgr, action->media.type); + } - /* Get Media type from the action */ - mediaType_changed = (TSIP_DIALOG_GET_SS(self)->media.type != action->media.type && action->media.type != tmedia_none); - if(self->msession_mgr && mediaType_changed){ - ret = tmedia_session_mgr_set_media_type(self->msession_mgr, action->media.type); - } + /* Appy media params received from the user */ + if(!TSK_LIST_IS_EMPTY(action->media.params)) { + ret = tmedia_session_mgr_set_3(self->msession_mgr, action->media.params); + } - /* Appy media params received from the user */ - if(!TSK_LIST_IS_EMPTY(action->media.params)){ - ret = tmedia_session_mgr_set_3(self->msession_mgr, action->media.params); - } + /* set MSRP callback */ + if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp) { + ret = tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); + } - /* set MSRP callback */ - if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp){ - ret = tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); - } + /* Cancel 100rel timer */ + TSIP_DIALOG_TIMER_CANCEL(100rel); - /* Cancel 100rel timer */ - TSIP_DIALOG_TIMER_CANCEL(100rel); + /* send 2xx OK */ + ret = send_RESPONSE(self, self->last_iInvite, 200, "OK", tsk_true); - /* send 2xx OK */ - ret = send_RESPONSE(self, self->last_iInvite, 200, "OK", tsk_true); - /* say we're waiting for the incoming ACK */ self->is_initial_iack_pending = tsk_true; - /* do not start the session until we get the ACK message - * http://code.google.com/p/doubango/issues/detail?id=157 - */ + /* do not start the session until we get the ACK message + * http://code.google.com/p/doubango/issues/detail?id=157 + */ /* do not start the session until we get at least one remote SDP * https://code.google.com/p/doubango/issues/detail?id=438 */ - // FIXME: (chrome) <-RTCWeb Breaker-> (chrome) do not work if media session is not started on i200 - // http://code.google.com/p/webrtc2sip/issues/detail?id=45 - if(/*TSIP_DIALOG_GET_STACK(self)->network.mode == tsip_stack_mode_webrtc2sip*/ TSIP_MESSAGE_HAS_CONTENT(self->last_iInvite)){ - ret = tsip_dialog_invite_msession_start(self); - } - - /* Session Timers */ - if(self->stimers.timer.timeout){ - if(self->stimers.is_refresher){ - /* RFC 4028 - 9. UAS Behavior - It is RECOMMENDED that this refresh be sent oncehalf the session interval has elapsed. - Additional procedures for this refresh are described in Section 10. - */ - tsip_dialog_invite_stimers_schedule(self, (self->stimers.timer.timeout*1000)/2); - } - else{ - tsip_dialog_invite_stimers_schedule(self, (self->stimers.timer.timeout*1000)); - } - } - - /* alert the user (dialog) */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - - return ret; + // FIXME: (chrome) <-RTCWeb Breaker-> (chrome) do not work if media session is not started on i200 + // http://code.google.com/p/webrtc2sip/issues/detail?id=45 + if(/*TSIP_DIALOG_GET_STACK(self)->network.mode == tsip_stack_mode_webrtc2sip*/ TSIP_MESSAGE_HAS_CONTENT(self->last_iInvite)) { + ret = tsip_dialog_invite_msession_start(self); + } + + /* Session Timers */ + if(self->stimers.timer.timeout) { + if(self->stimers.is_refresher) { + /* RFC 4028 - 9. UAS Behavior + It is RECOMMENDED that this refresh be sent oncehalf the session interval has elapsed. + Additional procedures for this refresh are described in Section 10. + */ + tsip_dialog_invite_stimers_schedule(self, (self->stimers.timer.timeout*1000)/2); + } + else { + tsip_dialog_invite_stimers_schedule(self, (self->stimers.timer.timeout*1000)); + } + } + + /* alert the user (dialog) */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + + return ret; } /* Ringing -> (oReject) -> Terminated */ int s0000_Ringing_2_Terminated_X_Reject(va_list *app) { - int ret; - short code; - const char* phrase; - char* reason = tsk_null; + int ret; + short code; + const char* phrase; + char* reason = tsk_null; - tsip_dialog_invite_t *self; - const tsip_action_t* action; + tsip_dialog_invite_t *self; + const tsip_action_t* action; - self = va_arg(*app, tsip_dialog_invite_t *); - va_arg(*app, const tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); + self = va_arg(*app, tsip_dialog_invite_t *); + va_arg(*app, const tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); - /* Cancel 100rel timer */ - TSIP_DIALOG_TIMER_CANCEL(100rel); + /* Cancel 100rel timer */ + TSIP_DIALOG_TIMER_CANCEL(100rel); - /* Send Reject */ - code = action->line_resp.code>=300 ? action->line_resp.code : 603; - phrase = action->line_resp.phrase ? action->line_resp.phrase : "Decline"; - tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); - ret = send_ERROR(self, self->last_iInvite, code, phrase, reason); - TSK_FREE(reason); + /* Send Reject */ + code = action->line_resp.code>=300 ? action->line_resp.code : 603; + phrase = action->line_resp.phrase ? action->line_resp.phrase : "Decline"; + tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); + ret = send_ERROR(self, self->last_iInvite, code, phrase, reason); + TSK_FREE(reason); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Terminated", tsip_event_code_dialog_terminated); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Terminated", tsip_event_code_dialog_terminated); - return ret; + return ret; } /* Ringing ->(iCANCEL) -> Terminated */ int s0000_Ringing_2_Terminated_X_iCANCEL(va_list *app) { - int ret; - tsip_response_t* response; + int ret; + tsip_response_t* response; - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); - if(!self->last_iInvite){ - /* silently ignore */ - return 0; - } + if(!self->last_iInvite) { + /* silently ignore */ + return 0; + } - /* Send 2xx for the CANCEL (Direct to Transport layer beacause CANCEL is a special case) */ - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))){ - ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, response); - TSK_OBJECT_SAFE_FREE(response); - } + /* Send 2xx for the CANCEL (Direct to Transport layer beacause CANCEL is a special case) */ + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))) { + ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, response); + TSK_OBJECT_SAFE_FREE(response); + } - /* Send Request Cancelled */ - ret = send_ERROR(self, self->last_iInvite, 487, "Request Cancelled", "SIP; cause=487; text=\"Request Cancelled\""); + /* Send Request Cancelled */ + ret = send_ERROR(self, self->last_iInvite, 487, "Request Cancelled", "SIP; cause=487; text=\"Request Cancelled\""); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Cancelled", tsip_event_code_dialog_terminated); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Call Cancelled", tsip_event_code_dialog_terminated); - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - return ret; + return ret; } /* Any ->(timer 100rel) -> Any */ int s0000_Any_2_Any_X_timer100rel(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - - int ret; - - if(!self->last_o1xxrel){ - /* silently ignore */ - return 0; - } - - /* resync timer */ - if((self->timer100rel.timeout *= 2) >= (64 * tsip_timers_getA())){ - TSK_DEBUG_ERROR("Sending reliable 1xx failed"); - return -2; - } - - /* resend reliable 1xx */ - if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), self->last_o1xxrel))){ - return ret; - } - else{ - /* schedule timer */ - TSIP_DIALOG_INVITE_TIMER_SCHEDULE(100rel); - } - - return ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + + int ret; + + if(!self->last_o1xxrel) { + /* silently ignore */ + return 0; + } + + /* resync timer */ + if((self->timer100rel.timeout *= 2) >= (64 * tsip_timers_getA())) { + TSK_DEBUG_ERROR("Sending reliable 1xx failed"); + return -2; + } + + /* resend reliable 1xx */ + if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), self->last_o1xxrel))) { + return ret; + } + else { + /* schedule timer */ + TSIP_DIALOG_INVITE_TIMER_SCHEDULE(100rel); + } + + return ret; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -766,25 +766,25 @@ int s0000_Any_2_Any_X_timer100rel(va_list *app) int send_UNSUPPORTED(tsip_dialog_invite_t* self, const tsip_request_t* request, const char* option) { - tsip_response_t *response; - - if(!self || !option){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 420, "Bad Extension", request))){ - // Add UnSupported header - tsip_message_add_headers(response, - TSIP_HEADER_DUMMY_VA_ARGS("Unsupported", option), - TSIP_HEADER_DUMMY_VA_ARGS("Reason", "SIP; cause=420; text=\"Bad Extension\""), - tsk_null - ); - - tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - return 0; + tsip_response_t *response; + + if(!self || !option) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 420, "Bad Extension", request))) { + // Add UnSupported header + tsip_message_add_headers(response, + TSIP_HEADER_DUMMY_VA_ARGS("Unsupported", option), + TSIP_HEADER_DUMMY_VA_ARGS("Reason", "SIP; cause=420; text=\"Bad Extension\""), + tsk_null + ); + + tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + return 0; } |