diff options
Diffstat (limited to 'tinySIP/src/dialogs/tsip_dialog_invite.timers.c')
-rwxr-xr-x | tinySIP/src/dialogs/tsip_dialog_invite.timers.c | 388 |
1 files changed, 194 insertions, 194 deletions
diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.timers.c b/tinySIP/src/dialogs/tsip_dialog_invite.timers.c index a8b279c..00743f2 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.timers.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.timers.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. * @@ -54,29 +54,29 @@ static int x0250_Any_2_Any_X_i422(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_is_refresher(tsip_dialog_invite_t* self, tsip_message_t* message) { - return self->stimers.is_refresher; + return self->stimers.is_refresher; } static tsk_bool_t _fsm_cond_is_not_refresher(tsip_dialog_invite_t* self, tsip_message_t* message) { - return !_fsm_cond_is_refresher(self, message); + return !_fsm_cond_is_refresher(self, message); } /* Init FSM */ int tsip_dialog_invite_stimers_init(tsip_dialog_invite_t *self) { - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - // Connected -> (timerRefresh && isRefresher) -> Connected - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_timerRefresh, _fsm_cond_is_refresher, _fsm_state_Connected, x0200_Connected_2_Connected_X_timerRefresh, "x0200_Connected_2_Connected_X_timerRefresh"), - // Connected -> (timerRefresh && !isRefresher) -> Trying (because we will send BYE) - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_timerRefresh, _fsm_cond_is_not_refresher, _fsm_state_Trying, x0201_Connected_2_Trying_X_timerRefresh, "x0201_Connected_2_Trying_X_timerRefresh"), - // Any -> (i422) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_i422, tsk_fsm_state_any, x0250_Any_2_Any_X_i422, "x0250_Any_2_Any_X_i422"), + // Connected -> (timerRefresh && isRefresher) -> Connected + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_timerRefresh, _fsm_cond_is_refresher, _fsm_state_Connected, x0200_Connected_2_Connected_X_timerRefresh, "x0200_Connected_2_Connected_X_timerRefresh"), + // Connected -> (timerRefresh && !isRefresher) -> Trying (because we will send BYE) + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_timerRefresh, _fsm_cond_is_not_refresher, _fsm_state_Trying, x0201_Connected_2_Trying_X_timerRefresh, "x0201_Connected_2_Trying_X_timerRefresh"), + // Any -> (i422) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_i422, tsk_fsm_state_any, x0250_Any_2_Any_X_i422, "x0250_Any_2_Any_X_i422"), - TSK_FSM_ADD_NULL()); + TSK_FSM_ADD_NULL()); - return 0; + return 0; } @@ -86,80 +86,80 @@ int tsip_dialog_invite_stimers_init(tsip_dialog_invite_t *self) int x0200_Connected_2_Connected_X_timerRefresh(va_list *app) { - /* We are the refresher and the session timedout - ==> Refresh the session - */ - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - int ret; - - /* RFC 4028 - 7.4. Generating Subsequent Session Refresh Requests - - A re-INVITE generated to refresh the session is a normal re-INVITE, - and an UPDATE generated to refresh a session is a normal UPDATE. If - a UAC knows that its peer supports the UPDATE method, it is - RECOMMENDED that UPDATE be used instead of a re-INVITE. A UA can - make this determination if it has seen an Allow header field from its - peer with the value 'UPDATE', or through a mid-dialog OPTIONS - request. It is RECOMMENDED that the UPDATE request not contain an - offer [4], but a re-INVITE SHOULD contain one, even if the details of - the session have not changed - */ - /* 2xx will be handled by tsip_dialog_invite_stimers_handle() */ - ret = send_INVITEorUPDATE(self, !self->support_update, tsk_false); - - return ret; + /* We are the refresher and the session timedout + ==> Refresh the session + */ + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + int ret; + + /* RFC 4028 - 7.4. Generating Subsequent Session Refresh Requests + + A re-INVITE generated to refresh the session is a normal re-INVITE, + and an UPDATE generated to refresh a session is a normal UPDATE. If + a UAC knows that its peer supports the UPDATE method, it is + RECOMMENDED that UPDATE be used instead of a re-INVITE. A UA can + make this determination if it has seen an Allow header field from its + peer with the value 'UPDATE', or through a mid-dialog OPTIONS + request. It is RECOMMENDED that the UPDATE request not contain an + offer [4], but a re-INVITE SHOULD contain one, even if the details of + the session have not changed + */ + /* 2xx will be handled by tsip_dialog_invite_stimers_handle() */ + ret = send_INVITEorUPDATE(self, !self->support_update, tsk_false); + + return ret; } int x0201_Connected_2_Trying_X_timerRefresh(va_list *app) { - /* We are not the refresher and the session timedout - ==> send BYE - */ - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - int ret; - - /* send BYE */ - ret = send_BYE(self); - - /* alert the user that the session timedout */ - - return ret; + /* We are not the refresher and the session timedout + ==> send BYE + */ + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + int ret; + + /* send BYE */ + ret = send_BYE(self); + + /* alert the user that the session timedout */ + + return ret; } // Any -> (i422) -> Any int x0250_Any_2_Any_X_i422(va_list *app) { - tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t* r422 = va_arg(*app, const tsip_response_t *); - - const tsip_header_Min_SE_t* Min_SE; - - /* RFC 4825 - 3. Overview of Operation - If the Session-Expires interval is too low for a proxy (i.e., lower - than the value of Min-SE that the proxy would wish to assert), the - proxy rejects the request with a 422 response. That response - contains a Min-SE header field identifying the minimum session - interval it is willing to support. The UAC will try again, this time - including the Min-SE header field in the request. The header field - contains the largest Min-SE header field it observed in all 422 - responses previously received. This way, the minimum timer meets the - constraints of all proxies along the path. - - RFC 4825 - 6. 422 Response Code Definition - The 422 response MUST contain a Min-SE header field with the minimum timer for that server. - */ - - if((Min_SE = (const tsip_header_Min_SE_t* )tsip_message_get_header(r422, tsip_htype_Min_SE))){ - self->stimers.minse = Min_SE->delta_seconds; - self->stimers.timer.timeout = Min_SE->delta_seconds; - } - else{ - TSK_DEBUG_ERROR("Invalid response (422 need Min-SE header)"); - return 0; /* Do not end the dialog */ - } - - /* send again the INVITE */ - return send_INVITE(self, tsk_false); + tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t* r422 = va_arg(*app, const tsip_response_t *); + + const tsip_header_Min_SE_t* Min_SE; + + /* RFC 4825 - 3. Overview of Operation + If the Session-Expires interval is too low for a proxy (i.e., lower + than the value of Min-SE that the proxy would wish to assert), the + proxy rejects the request with a 422 response. That response + contains a Min-SE header field identifying the minimum session + interval it is willing to support. The UAC will try again, this time + including the Min-SE header field in the request. The header field + contains the largest Min-SE header field it observed in all 422 + responses previously received. This way, the minimum timer meets the + constraints of all proxies along the path. + + RFC 4825 - 6. 422 Response Code Definition + The 422 response MUST contain a Min-SE header field with the minimum timer for that server. + */ + + if((Min_SE = (const tsip_header_Min_SE_t* )tsip_message_get_header(r422, tsip_htype_Min_SE))) { + self->stimers.minse = Min_SE->delta_seconds; + self->stimers.timer.timeout = Min_SE->delta_seconds; + } + else { + TSK_DEBUG_ERROR("Invalid response (422 need Min-SE header)"); + return 0; /* Do not end the dialog */ + } + + /* send again the INVITE */ + return send_INVITE(self, tsk_false); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -173,130 +173,130 @@ int x0250_Any_2_Any_X_i422(va_list *app) /* cancel the timer */ int tsip_dialog_invite_stimers_cancel(tsip_dialog_invite_t* self) { - return tsk_timer_mgr_global_cancel(self->stimers.timer.id); + return tsk_timer_mgr_global_cancel(self->stimers.timer.id); } /* schedule the timer */ int tsip_dialog_invite_stimers_schedule(tsip_dialog_invite_t* self, uint64_t timeout) { - /* Used in SIP requests ==> do not change the value - self->stimers.timer.timeout = timeout; - */ - self->stimers.timer.id = tsk_timer_mgr_global_schedule(timeout, TSK_TIMER_CALLBACK_F(tsip_dialog_invite_timer_callback), self); + /* Used in SIP requests ==> do not change the value + self->stimers.timer.timeout = timeout; + */ + self->stimers.timer.id = tsk_timer_mgr_global_schedule(timeout, TSK_TIMER_CALLBACK_F(tsip_dialog_invite_timer_callback), self); - return 0; + return 0; } /* handle requests/responses */ int tsip_dialog_invite_stimers_handle(tsip_dialog_invite_t* self, const tsip_message_t* message) { - /* It's up to the caller to check that (self->stimers.timer.timeout is >0) - and message is INVITE or UPDATE or 2xxINVITE or 2xxUPDATE - */ - - int ret = 0; - const tsip_header_Session_Expires_t* hdr_SessionExpires; - - if(!self || !message){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!self->stimers.timer.timeout){ - /* guard for stupide callers */ - return 0; - } - /* reUPDATE or reINVITE */ - if(TSIP_MESSAGE_IS_REQUEST(message) && (TSIP_REQUEST_IS_UPDATE(message) || TSIP_REQUEST_IS_INVITE(message))){ - if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))){ - if(hdr_SessionExpires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE){ - self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; - ret = send_RESPONSE(self, message, 422, "Session Interval Too Small"); - } - else{ - 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"); - } - } - } - /* 2xx */ - else if(TSIP_MESSAGE_IS_RESPONSE(message) && (TSIP_RESPONSE_IS_TO_INVITE(message) || TSIP_RESPONSE_IS_TO_UPDATE(message))){ - if(!TSIP_RESPONSE_IS_2XX(message)){ - /* guard for stupide callers */ - return 0; - } - /* Process the response only if it includes "Require: timer" - - RFC 4028 - 7.2. Processing a 2xx Response - When a 2xx response to a session refresh request arrives, it may or - may not contain a Require header field with the value 'timer'. If it - does, the UAC MUST look for the Session-Expires header field to - process the response. - - If there was a Require header field in the response with the value - 'timer', the Session-Expires header field will always be present. - UACs MUST be prepared to receive a Session-Expires header field in a - response, even if none were present in the request. The 'refresher' - parameter will be present in the Session-Expires header field, - indicating who will perform the refreshes. The UAC MUST set the - identity of the refresher to the value of this parameter. If the - parameter contains the value 'uac', the UAC will perform them. - */ - if(tsip_message_required(message, "timer")){ - if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))){ - if(hdr_SessionExpires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE){ - self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; - ret = send_RESPONSE(self, message, 422, "Interval Too short"); - } - else{ - 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, "uac"); - self->supported.timer = (self->stimers.timer.timeout != 0); - self->required.timer = self->supported.timer; - } - } - else{ - self->stimers.timer.timeout = 0; /* turned-off */ - self->supported.timer = tsk_false; - self->required.timer = tsk_false; - ret = send_RESPONSE(self, message, 481, "Session-Expires header is missing"); - return 0; - } - } - else{ - /* - RFC 4028 - 7.2. Processing a 2xx Response - If the 2xx response did not contain a Session-Expires header field, - there is no session expiration. In this case, no refreshes need to - be sent. A 2xx without a Session-Expires can come for both initial - and subsequent session refresh requests. This means that the session - timer can be 'turned-off' in mid dialog by receiving a response - without a Session-Expires header field. - */ - self->stimers.timer.timeout = 0; /* turned-off */ - self->supported.timer = tsk_false; - self->required.timer = tsk_false; - } - } - - /* Cancel timeout */ - tsip_dialog_invite_stimers_cancel(self); - - /* schedule timer */ - 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)); - } - } - - return ret; + /* It's up to the caller to check that (self->stimers.timer.timeout is >0) + and message is INVITE or UPDATE or 2xxINVITE or 2xxUPDATE + */ + + int ret = 0; + const tsip_header_Session_Expires_t* hdr_SessionExpires; + + if(!self || !message) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->stimers.timer.timeout) { + /* guard for stupide callers */ + return 0; + } + /* reUPDATE or reINVITE */ + if(TSIP_MESSAGE_IS_REQUEST(message) && (TSIP_REQUEST_IS_UPDATE(message) || TSIP_REQUEST_IS_INVITE(message))) { + if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))) { + if(hdr_SessionExpires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE) { + self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; + ret = send_RESPONSE(self, message, 422, "Session Interval Too Small"); + } + else { + 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"); + } + } + } + /* 2xx */ + else if(TSIP_MESSAGE_IS_RESPONSE(message) && (TSIP_RESPONSE_IS_TO_INVITE(message) || TSIP_RESPONSE_IS_TO_UPDATE(message))) { + if(!TSIP_RESPONSE_IS_2XX(message)) { + /* guard for stupide callers */ + return 0; + } + /* Process the response only if it includes "Require: timer" + + RFC 4028 - 7.2. Processing a 2xx Response + When a 2xx response to a session refresh request arrives, it may or + may not contain a Require header field with the value 'timer'. If it + does, the UAC MUST look for the Session-Expires header field to + process the response. + + If there was a Require header field in the response with the value + 'timer', the Session-Expires header field will always be present. + UACs MUST be prepared to receive a Session-Expires header field in a + response, even if none were present in the request. The 'refresher' + parameter will be present in the Session-Expires header field, + indicating who will perform the refreshes. The UAC MUST set the + identity of the refresher to the value of this parameter. If the + parameter contains the value 'uac', the UAC will perform them. + */ + if(tsip_message_required(message, "timer")) { + if((hdr_SessionExpires = (const tsip_header_Session_Expires_t*)tsip_message_get_header(message, tsip_htype_Session_Expires))) { + if(hdr_SessionExpires->delta_seconds < TSIP_SESSION_EXPIRES_MIN_VALUE) { + self->stimers.minse = TSIP_SESSION_EXPIRES_MIN_VALUE; + ret = send_RESPONSE(self, message, 422, "Interval Too short"); + } + else { + 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, "uac"); + self->supported.timer = (self->stimers.timer.timeout != 0); + self->required.timer = self->supported.timer; + } + } + else { + self->stimers.timer.timeout = 0; /* turned-off */ + self->supported.timer = tsk_false; + self->required.timer = tsk_false; + ret = send_RESPONSE(self, message, 481, "Session-Expires header is missing"); + return 0; + } + } + else { + /* + RFC 4028 - 7.2. Processing a 2xx Response + If the 2xx response did not contain a Session-Expires header field, + there is no session expiration. In this case, no refreshes need to + be sent. A 2xx without a Session-Expires can come for both initial + and subsequent session refresh requests. This means that the session + timer can be 'turned-off' in mid dialog by receiving a response + without a Session-Expires header field. + */ + self->stimers.timer.timeout = 0; /* turned-off */ + self->supported.timer = tsk_false; + self->required.timer = tsk_false; + } + } + + /* Cancel timeout */ + tsip_dialog_invite_stimers_cancel(self); + + /* schedule timer */ + 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)); + } + } + + return ret; } |