diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2016-02-23 22:00:35 +0100 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2016-02-23 22:00:35 +0100 |
commit | 50dfb4359619563012997bc3ddafb7667741066c (patch) | |
tree | db234c1edc3240a653363b5735fc4077af4b8720 /tinySIP/src | |
parent | 94b2219209038e05dd26395f6fb700be4d1062c0 (diff) | |
download | doubango-50dfb4359619563012997bc3ddafb7667741066c.zip doubango-50dfb4359619563012997bc3ddafb7667741066c.tar.gz |
Add new QoS implementation
Code formatting
Diffstat (limited to 'tinySIP/src')
100 files changed, 45781 insertions, 45164 deletions
diff --git a/tinySIP/src/api/tsip_api_common.c b/tinySIP/src/api/tsip_api_common.c index 4261fd5..a325385 100755 --- a/tinySIP/src/api/tsip_api_common.c +++ b/tinySIP/src/api/tsip_api_common.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 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. * @@ -39,96 +39,96 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) /* Local functions */ int _tsip_api_common_any(const tsip_ssession_handle_t *ss, tsip_action_type_t type, va_list* app); -/* internal function used to execute any user action +/* internal function used to execute any user action * can only handle session with dialogs */ int _tsip_api_common_any(const tsip_ssession_handle_t *ss, tsip_action_type_t type, va_list* app) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - /* execute action */ - if((action = _tsip_action_create(type, app))){ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + /* execute action */ + if((action = _tsip_action_create(type, app))) { + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + return ret; } /**@ingroup tsip_action_group * Rejects an incoming request. * @param ss The SIP Session managing the dialog on which the request has been received. -* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). +* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). * MUST always ends with @ref TSIP_ACTION_SET_NULL(). * @retval Zero if succeed and non-zero error code otherwise. */ int tsip_api_common_reject(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; + int ret = -1; + va_list ap; - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_reject, &ap))){ - TSK_DEBUG_ERROR("Reject() failed."); - } - va_end(ap); + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_reject, &ap))) { + TSK_DEBUG_ERROR("Reject() failed."); + } + va_end(ap); - return ret; + return ret; } /**@ingroup tsip_action_group * Hangs up a session. * @param ss The SIP Session to hang-up. Will send an unREGISTER or unSUBSCRIBE or unPUBLISH or -* BYE etc depending on the type of the SIP dialog managed by the session. -* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). +* BYE etc depending on the type of the SIP dialog managed by the session. +* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). * MUST always ends with @ref TSIP_ACTION_SET_NULL(). * @retval Zero if succeed and non-zero error code otherwise. */ int tsip_api_common_hangup(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; + int ret = -1; + va_list ap; - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_hangup, &ap))){ - TSK_DEBUG_ERROR("Hang-up() failed."); - } - va_end(ap); + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_hangup, &ap))) { + TSK_DEBUG_ERROR("Hang-up() failed."); + } + va_end(ap); - return ret; + return ret; } /**@ingroup tsip_action_group * Accepts an incoming request. * @param ss The SIP Session managing the dialog on which the request has been received. -* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). +* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). * MUST always ends with @ref TSIP_ACTION_SET_NULL(). * @retval Zero if succeed and non-zero error code otherwise. */ int tsip_api_common_accept(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; + int ret = -1; + va_list ap; - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_accept, &ap))){ - TSK_DEBUG_ERROR("Accept() failed."); - } - va_end(ap); + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_accept, &ap))) { + TSK_DEBUG_ERROR("Accept() failed."); + } + va_end(ap); - return ret; + return ret; } diff --git a/tinySIP/src/api/tsip_api_info.c b/tinySIP/src/api/tsip_api_info.c index ec20b8b..37265da 100755 --- a/tinySIP/src/api/tsip_api_info.c +++ b/tinySIP/src/api/tsip_api_info.c @@ -2,19 +2,19 @@ * Copyright (C) 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. * @@ -43,47 +43,47 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) int tsip_info_event_signal(tsip_info_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_info_event_t* sipevent = TSIP_INFO_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_info); + tsip_info_event_t* sipevent = TSIP_INFO_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_info); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_info_send_info(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - /* action */ - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_info_send, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_INFO, ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + /* action */ + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_info_send, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_INFO, ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } @@ -103,32 +103,31 @@ int tsip_api_info_send_info(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_info_event_ctor(tsk_object_t * self, va_list * app) { - tsip_info_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_info_event_type_t); - } - return self; + tsip_info_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_info_event_type_t); + } + return self; } static tsk_object_t* tsip_info_event_dtor(tsk_object_t * self) -{ - tsip_info_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_info_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_info_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_info_event_def_s = -{ - sizeof(tsip_info_event_t), - tsip_info_event_ctor, - tsip_info_event_dtor, - tsip_info_event_cmp, +static const tsk_object_def_t tsip_info_event_def_s = { + sizeof(tsip_info_event_t), + tsip_info_event_ctor, + tsip_info_event_dtor, + tsip_info_event_cmp, }; const tsk_object_def_t *tsip_info_event_def_t = &tsip_info_event_def_s; diff --git a/tinySIP/src/api/tsip_api_invite.c b/tinySIP/src/api/tsip_api_invite.c index 530eb67..9cdaa9f 100755 --- a/tinySIP/src/api/tsip_api_invite.c +++ b/tinySIP/src/api/tsip_api_invite.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 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. * @@ -45,274 +45,274 @@ extern int _tsip_api_common_any(const tsip_ssession_handle_t *ss, tsip_action_ty int tsip_invite_event_signal(tsip_invite_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_invite_event_t* sipevent = TSIP_INVITE_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_invite); + tsip_invite_event_t* sipevent = TSIP_INVITE_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_invite); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_invite_send_invite(const tsip_ssession_handle_t *ss, tmedia_type_t type, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, type); - if((action = _tsip_action_create(tsip_atype_invite, &ap))){ - tsk_bool_t new_dialog = tsk_false; - /* Media type */ - action->media.type = type; - - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_INVITE, ss); - new_dialog = tsk_true; - } - if(!(ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action))){ - if(new_dialog){ // otherwise we are trying to refresh the media type and the type will be updated if 200 OK - TSIP_SSESSION(_ss)->media.type = type; // Update Session Media Type - } - } - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, type); + if((action = _tsip_action_create(tsip_atype_invite, &ap))) { + tsk_bool_t new_dialog = tsk_false; + /* Media type */ + action->media.type = type; + + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_INVITE, ss); + new_dialog = tsk_true; + } + if(!(ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action))) { + if(new_dialog) { // otherwise we are trying to refresh the media type and the type will be updated if 200 OK + TSIP_SSESSION(_ss)->media.type = type; // Update Session Media Type + } + } + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_info(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - va_list ap; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, ss); - /* execute action */ - if((action = _tsip_action_create(tsip_atype_info_send, &ap))){ - /* Perform action */ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + va_list ap; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, ss); + /* execute action */ + if((action = _tsip_action_create(tsip_atype_info_send, &ap))) { + /* Perform action */ + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_hold(const tsip_ssession_handle_t *ss, tmedia_type_t type, ...) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - va_list ap; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, type); - /* execute action */ - if((action = _tsip_action_create(tsip_atype_hold, &ap))){ - /* Media type */ - action->media.type = type; - /* Perform action */ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + va_list ap; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, type); + /* execute action */ + if((action = _tsip_action_create(tsip_atype_hold, &ap))) { + /* Media type */ + action->media.type = type; + /* Perform action */ + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_resume(const tsip_ssession_handle_t *ss, tmedia_type_t type, ...) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - va_list ap; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, type); - /* execute action */ - if((action = _tsip_action_create(tsip_atype_resume, &ap))){ - /* Media type */ - action->media.type = type; - /* Perform action */ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + va_list ap; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, type); + /* execute action */ + if((action = _tsip_action_create(tsip_atype_resume, &ap))) { + /* Media type */ + action->media.type = type; + /* Perform action */ + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_large_message(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; - - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_lmessage, &ap))){ - TSK_DEBUG_ERROR("Failed to send MSRP message"); - } - va_end(ap); - - return ret; + int ret = -1; + va_list ap; + + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_lmessage, &ap))) { + TSK_DEBUG_ERROR("Failed to send MSRP message"); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_ect(const tsip_ssession_handle_t *ss, const char* toUri, ...) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - va_list ap; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack || !toUri){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, toUri); - /* execute action */ - if((action = _tsip_action_create(tsip_atype_ect, &ap))){ - /* Refer-To */ - action->ect.to = tsk_strdup(toUri); - /* Perform action */ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + va_list ap; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack || !toUri) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, toUri); + /* execute action */ + if((action = _tsip_action_create(tsip_atype_ect, &ap))) { + /* Refer-To */ + action->ect.to = tsk_strdup(toUri); + /* Perform action */ + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_ect_accept(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; - - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_ect_accept, &ap))){ - TSK_DEBUG_ERROR("Failed to accept incoming ECT"); - } - va_end(ap); - - return ret; + int ret = -1; + va_list ap; + + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_ect_accept, &ap))) { + TSK_DEBUG_ERROR("Failed to accept incoming ECT"); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_ect_reject(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; - - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_ect_reject, &ap))){ - TSK_DEBUG_ERROR("Failed to reject incoming ECT"); - } - va_end(ap); - - return ret; + int ret = -1; + va_list ap; + + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_ect_reject, &ap))) { + TSK_DEBUG_ERROR("Failed to reject incoming ECT"); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_dtmf(const tsip_ssession_handle_t *ss, int event, ...) { - int ret = -1; - tsip_action_t* action; - const tsip_ssession_t* _ss; - va_list ap; - - /* Checks for validity */ - if(!(_ss = ss) || !_ss->stack || (event <0 || event>15)){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, event); - /* execute action */ - if((action = _tsip_action_create(tsip_atype_dtmf_send, &ap))){ - /* Event */ - action->dtmf.event = event; - /* Perform action */ - ret = tsip_ssession_handle(_ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + int ret = -1; + tsip_action_t* action; + const tsip_ssession_t* _ss; + va_list ap; + + /* Checks for validity */ + if(!(_ss = ss) || !_ss->stack || (event <0 || event>15)) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, event); + /* execute action */ + if((action = _tsip_action_create(tsip_atype_dtmf_send, &ap))) { + /* Event */ + action->dtmf.event = event; + /* Perform action */ + ret = tsip_ssession_handle(_ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_invite_send_bye(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; + int ret = -1; + va_list ap; - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_bye, &ap))){ - TSK_DEBUG_ERROR("Bye() failed."); - } - va_end(ap); + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_bye, &ap))) { + TSK_DEBUG_ERROR("Bye() failed."); + } + va_end(ap); - return ret; + return ret; } @@ -332,32 +332,31 @@ int tsip_api_invite_send_bye(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_invite_event_ctor(tsk_object_t * self, va_list * app) { - tsip_invite_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_invite_event_type_t); - } - return self; + tsip_invite_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_invite_event_type_t); + } + return self; } static tsk_object_t* tsip_invite_event_dtor(tsk_object_t * self) -{ - tsip_invite_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_invite_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_invite_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_invite_event_def_s = -{ - sizeof(tsip_invite_event_t), - tsip_invite_event_ctor, - tsip_invite_event_dtor, - tsip_invite_event_cmp, +static const tsk_object_def_t tsip_invite_event_def_s = { + sizeof(tsip_invite_event_t), + tsip_invite_event_ctor, + tsip_invite_event_dtor, + tsip_invite_event_cmp, }; const tsk_object_def_t *tsip_invite_event_def_t = &tsip_invite_event_def_s; diff --git a/tinySIP/src/api/tsip_api_message.c b/tinySIP/src/api/tsip_api_message.c index 232e9c6..1c65e50 100755 --- a/tinySIP/src/api/tsip_api_message.c +++ b/tinySIP/src/api/tsip_api_message.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 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. * @@ -43,47 +43,47 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) int tsip_message_event_signal(tsip_message_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_message_event_t* sipevent = TSIP_MESSAGE_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message); + tsip_message_event_t* sipevent = TSIP_MESSAGE_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_message_send_message(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - /* action */ - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_message_send, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + /* action */ + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_message_send, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } @@ -103,32 +103,31 @@ int tsip_api_message_send_message(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_message_event_ctor(tsk_object_t * self, va_list * app) { - tsip_message_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_message_event_type_t); - } - return self; + tsip_message_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_message_event_type_t); + } + return self; } static tsk_object_t* tsip_message_event_dtor(tsk_object_t * self) -{ - tsip_message_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_message_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_message_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_message_event_def_s = -{ - sizeof(tsip_message_event_t), - tsip_message_event_ctor, - tsip_message_event_dtor, - tsip_message_event_cmp, +static const tsk_object_def_t tsip_message_event_def_s = { + sizeof(tsip_message_event_t), + tsip_message_event_ctor, + tsip_message_event_dtor, + tsip_message_event_cmp, }; const tsk_object_def_t *tsip_message_event_def_t = &tsip_message_event_def_s; diff --git a/tinySIP/src/api/tsip_api_options.c b/tinySIP/src/api/tsip_api_options.c index df87a4d..029f763 100755 --- a/tinySIP/src/api/tsip_api_options.c +++ b/tinySIP/src/api/tsip_api_options.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 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. * @@ -43,46 +43,46 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) int tsip_options_event_signal(tsip_options_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_options_event_t* sipevent = TSIP_OPTIONS_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_options); + tsip_options_event_t* sipevent = TSIP_OPTIONS_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_options); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_options_send_options(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_options_send, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_OPTIONS, ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_options_send, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_OPTIONS, ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } @@ -102,32 +102,31 @@ int tsip_api_options_send_options(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_options_event_ctor(tsk_object_t * self, va_list * app) { - tsip_options_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_options_event_type_t); - } - return self; + tsip_options_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_options_event_type_t); + } + return self; } static tsk_object_t* tsip_options_event_dtor(tsk_object_t * self) -{ - tsip_options_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_options_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_options_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_options_event_def_s = -{ - sizeof(tsip_options_event_t), - tsip_options_event_ctor, - tsip_options_event_dtor, - tsip_options_event_cmp, +static const tsk_object_def_t tsip_options_event_def_s = { + sizeof(tsip_options_event_t), + tsip_options_event_ctor, + tsip_options_event_dtor, + tsip_options_event_cmp, }; const tsk_object_def_t *tsip_options_event_def_t = &tsip_options_event_def_s; diff --git a/tinySIP/src/api/tsip_api_publish.c b/tinySIP/src/api/tsip_api_publish.c index 916ed6f..86fd60f 100755 --- a/tinySIP/src/api/tsip_api_publish.c +++ b/tinySIP/src/api/tsip_api_publish.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 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. * @@ -43,74 +43,74 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) int tsip_publish_event_signal(tsip_publish_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_publish_event_t* sipevent = TSIP_PUBLISH_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_publish); + tsip_publish_event_t* sipevent = TSIP_PUBLISH_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_publish); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_publish_send_publish(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_publish, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_PUBLISH, ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_publish, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_PUBLISH, ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_publish_send_unpublish(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack is running */ - if(!TSK_RUNNABLE(_ss->stack)->running){ - TSK_DEBUG_ERROR("Stack not running."); - return -2; - } - - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_unpublish, &ap))){ - ret = tsip_ssession_handle(ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return 0; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack is running */ + if(!TSK_RUNNABLE(_ss->stack)->running) { + TSK_DEBUG_ERROR("Stack not running."); + return -2; + } + + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_unpublish, &ap))) { + ret = tsip_ssession_handle(ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return 0; } @@ -128,32 +128,31 @@ int tsip_api_publish_send_unpublish(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_publish_event_ctor(tsk_object_t * self, va_list * app) { - tsip_publish_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_publish_event_type_t); - } - return self; + tsip_publish_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_publish_event_type_t); + } + return self; } static tsk_object_t* tsip_publish_event_dtor(tsk_object_t * self) -{ - tsip_publish_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_publish_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_publish_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_publish_event_def_s = -{ - sizeof(tsip_publish_event_t), - tsip_publish_event_ctor, - tsip_publish_event_dtor, - tsip_publish_event_cmp, +static const tsk_object_def_t tsip_publish_event_def_s = { + sizeof(tsip_publish_event_t), + tsip_publish_event_ctor, + tsip_publish_event_dtor, + tsip_publish_event_cmp, }; const tsk_object_def_t *tsip_publish_event_def_t = &tsip_publish_event_def_s; diff --git a/tinySIP/src/api/tsip_api_register.c b/tinySIP/src/api/tsip_api_register.c index 4d61632..5b5c579 100755 --- a/tinySIP/src/api/tsip_api_register.c +++ b/tinySIP/src/api/tsip_api_register.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 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. * @@ -47,78 +47,78 @@ extern int _tsip_api_common_any(const tsip_ssession_handle_t *ss, tsip_action_ty /* internal function used to signal evant from REGISTER dialog to user app */ int tsip_register_event_signal(tsip_register_event_type_t type, tsip_ssession_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_register_event_t* sipevent = TSIP_REGISTER_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_register); + tsip_register_event_t* sipevent = TSIP_REGISTER_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_register); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(ss->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(ss->stack), sipevent); - return 0; + return 0; } /**@ingroup tsip_action_group * Sends SIP REGISTER request. If the session is already established, the same dialog will * be used (refresh). * @param ss The SIP Session managing the REGISTER dialog. -* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). +* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). * MUST always ends with @ref TSIP_ACTION_SET_NULL(). * @retval Zero if succeed and non-zero error code otherwise. * @sa @ref tsip_api_register_send_unregister */ int tsip_api_register_send_register(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - /* performs action */ - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_register, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, _ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_REGISTER, _ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - TSK_OBJECT_SAFE_FREE(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + /* performs action */ + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_register, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, _ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_REGISTER, _ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + TSK_OBJECT_SAFE_FREE(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } /**@ingroup tsip_action_group * Sends SIP unREGISTER request (expires=0). The session should be already established. * @param ss The SIP Session managing the REGISTER dialog. -* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). +* @param ... Any TSIP_ACTION_SET_*() macros. e.g. @ref TSIP_ACTION_SET_HEADER(). * MUST always ends with @ref TSIP_ACTION_SET_NULL(). * @retval Zero if succeed and non-zero error code otherwise. * @sa @ref tsip_api_register_send_register */ int tsip_api_register_send_unregister(const tsip_ssession_handle_t *ss, ...) { - int ret = -1; - va_list ap; + int ret = -1; + va_list ap; - va_start(ap, ss); - if((ret = _tsip_api_common_any(ss, tsip_atype_unregister, &ap))){ - TSK_DEBUG_ERROR("unREGISTER() failed."); - } - va_end(ap); + va_start(ap, ss); + if((ret = _tsip_api_common_any(ss, tsip_atype_unregister, &ap))) { + TSK_DEBUG_ERROR("unREGISTER() failed."); + } + va_end(ap); - return ret; + return ret; } @@ -135,32 +135,31 @@ int tsip_api_register_send_unregister(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_register_event_ctor(tsk_object_t * self, va_list * app) { - tsip_register_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_register_event_type_t); - } - return self; + tsip_register_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_register_event_type_t); + } + return self; } static tsk_object_t* tsip_register_event_dtor(tsk_object_t * self) -{ - tsip_register_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_register_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_register_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_register_event_def_s = -{ - sizeof(tsip_register_event_t), - tsip_register_event_ctor, - tsip_register_event_dtor, - tsip_register_event_cmp, +static const tsk_object_def_t tsip_register_event_def_s = { + sizeof(tsip_register_event_t), + tsip_register_event_ctor, + tsip_register_event_dtor, + tsip_register_event_cmp, }; const tsk_object_def_t *tsip_register_event_def_t = &tsip_register_event_def_s; diff --git a/tinySIP/src/api/tsip_api_subscribe.c b/tinySIP/src/api/tsip_api_subscribe.c index 867b258..c0f8c43 100755 --- a/tinySIP/src/api/tsip_api_subscribe.c +++ b/tinySIP/src/api/tsip_api_subscribe.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 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. * @@ -44,74 +44,74 @@ extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app) int tsip_subscribe_event_signal(tsip_subscribe_event_type_t type, tsip_ssession_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { - tsip_subscribe_event_t* sipevent = TSIP_SUBSCRIBE_EVENT_CREATE(type); - tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_subscribe); + tsip_subscribe_event_t* sipevent = TSIP_SUBSCRIBE_EVENT_CREATE(type); + tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_subscribe); - TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); + TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); - return 0; + return 0; } int tsip_api_subscribe_send_subscribe(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - tsip_dialog_t* dialog; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack has been started */ - if(!TSK_RUNNABLE(_ss->stack)->started){ - TSK_DEBUG_ERROR("Stack not started."); - return -2; - } - - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_subscribe, &ap))){ - if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ - dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_SUBSCRIBE, ss); - } - ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); - - tsk_object_unref(dialog); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return ret; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + tsip_dialog_t* dialog; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack has been started */ + if(!TSK_RUNNABLE(_ss->stack)->started) { + TSK_DEBUG_ERROR("Stack not started."); + return -2; + } + + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_subscribe, &ap))) { + if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))) { + dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_SUBSCRIBE, ss); + } + ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); + + tsk_object_unref(dialog); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return ret; } int tsip_api_subscribe_send_unsubscribe(const tsip_ssession_handle_t *ss, ...) { - const tsip_ssession_t* _ss; - va_list ap; - tsip_action_t* action; - int ret = -1; - - if(!(_ss = ss) || !_ss->stack){ - TSK_DEBUG_ERROR("Invalid parameter."); - return ret; - } - - /* Checks if the stack is running */ - if(!TSK_RUNNABLE(_ss->stack)->running){ - TSK_DEBUG_ERROR("Stack not running."); - return -2; - } - - va_start(ap, ss); - if((action = _tsip_action_create(tsip_atype_unsubscribe, &ap))){ - ret = tsip_ssession_handle(ss, action); - TSK_OBJECT_SAFE_FREE(action); - } - va_end(ap); - - return 0; + const tsip_ssession_t* _ss; + va_list ap; + tsip_action_t* action; + int ret = -1; + + if(!(_ss = ss) || !_ss->stack) { + TSK_DEBUG_ERROR("Invalid parameter."); + return ret; + } + + /* Checks if the stack is running */ + if(!TSK_RUNNABLE(_ss->stack)->running) { + TSK_DEBUG_ERROR("Stack not running."); + return -2; + } + + va_start(ap, ss); + if((action = _tsip_action_create(tsip_atype_unsubscribe, &ap))) { + ret = tsip_ssession_handle(ss, action); + TSK_OBJECT_SAFE_FREE(action); + } + va_end(ap); + + return 0; } @@ -129,32 +129,31 @@ int tsip_api_subscribe_send_unsubscribe(const tsip_ssession_handle_t *ss, ...) // static tsk_object_t* tsip_subscribe_event_ctor(tsk_object_t * self, va_list * app) { - tsip_subscribe_event_t *sipevent = self; - if(sipevent){ - sipevent->type = va_arg(*app, tsip_subscribe_event_type_t); - } - return self; + tsip_subscribe_event_t *sipevent = self; + if(sipevent) { + sipevent->type = va_arg(*app, tsip_subscribe_event_type_t); + } + return self; } static tsk_object_t* tsip_subscribe_event_dtor(tsk_object_t * self) -{ - tsip_subscribe_event_t *sipevent = self; - if(sipevent){ - tsip_event_deinit(TSIP_EVENT(sipevent)); - } - return self; +{ + tsip_subscribe_event_t *sipevent = self; + if(sipevent) { + tsip_event_deinit(TSIP_EVENT(sipevent)); + } + return self; } static int tsip_subscribe_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_subscribe_event_def_s = -{ - sizeof(tsip_subscribe_event_t), - tsip_subscribe_event_ctor, - tsip_subscribe_event_dtor, - tsip_subscribe_event_cmp, +static const tsk_object_def_t tsip_subscribe_event_def_s = { + sizeof(tsip_subscribe_event_t), + tsip_subscribe_event_ctor, + tsip_subscribe_event_dtor, + tsip_subscribe_event_cmp, }; const tsk_object_def_t *tsip_subscribe_event_def_t = &tsip_subscribe_event_def_s; diff --git a/tinySIP/src/authentication/tsip_challenge.c b/tinySIP/src/authentication/tsip_challenge.c index bfe39ee..023c4bf 100755 --- a/tinySIP/src/authentication/tsip_challenge.c +++ b/tinySIP/src/authentication/tsip_challenge.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 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. * @@ -52,33 +52,32 @@ /** Creates new challenge object. */ tsip_challenge_t* tsip_challenge_create(tsip_stack_t* stack, tsk_bool_t isproxy, const char* scheme, const char* realm, const char* nonce, const char* opaque, const char* algorithm, const char* qop) { - return tsk_object_new(tsip_challenge_def_t, stack, isproxy,scheme, realm, nonce, opaque, algorithm, qop); + return tsk_object_new(tsip_challenge_def_t, stack, isproxy,scheme, realm, nonce, opaque, algorithm, qop); } /** Creates new challenge object (with default values). */ tsip_challenge_t* tsip_challenge_create_null(tsip_stack_t* stack) { - return tsip_challenge_create(stack, tsk_false, tsk_null, tsk_null, tsk_null, tsk_null, tsk_null, tsk_null); + return tsip_challenge_create(stack, tsk_false, tsk_null, tsk_null, tsk_null, tsk_null, tsk_null, tsk_null); } int tsip_challenge_reset_cnonce(tsip_challenge_t *self) { - if(self){ - if(self->qop) /* client nonce is only used if qop=auth, auth-int or both */ - { + if(self) { + if(self->qop) { /* client nonce is only used if qop=auth, auth-int or both */ #if 0 - memcpy(self->cnonce, "ecb1d3f6931803ce7ae68099cb946594", 32); + memcpy(self->cnonce, "ecb1d3f6931803ce7ae68099cb946594", 32); #else - tsk_istr_t istr; - - tsk_strrandom(&istr); - tsk_md5compute(istr, tsk_strlen(istr), &self->cnonce); + tsk_istr_t istr; + + tsk_strrandom(&istr); + tsk_md5compute(istr, tsk_strlen(istr), &self->cnonce); #endif - self->nc = 1; - } - } - return -1; + self->nc = 1; + } + } + return -1; } //3GPP TS 35.205/6/7/8/9 and RFC 3310 @@ -87,132 +86,132 @@ int tsip_challenge_get_akares(tsip_challenge_t *self, char const *password, char #define SQN_XOR_AK() (AUTN + 0) #define SERVER_DATA() (nonce + AKA_RAND_SIZE + AKA_AUTN_SIZE) - // § ==> XOR - // || ==> append - - AKA_RES_T akares; - - int ret = -1; - tsk_size_t n; - char *nonce = tsk_null; - - AKA_XXX_DECLARE(RAND); - AKA_XXX_DECLARE(AK); - AKA_XXX_DECLARE(AMF); - AKA_XXX_DECLARE(CK); - AKA_XXX_DECLARE(IK); - AKA_XXX_DECLARE(K); - AKA_XXX_DECLARE(SQN); - AKA_XXX_DECLARE(MAC_A); - AKA_XXX_DECLARE(AUTN); - - AKA_XXX_BZERO(RAND); - AKA_XXX_BZERO(AK); - AKA_XXX_BZERO(AMF); - AKA_XXX_BZERO(CK); - AKA_XXX_BZERO(IK); - AKA_XXX_BZERO(K); - AKA_XXX_BZERO(SQN); - AKA_XXX_BZERO(MAC_A); - AKA_XXX_BZERO(AUTN); - - /* RFC 3310 subclause 3.2: nonce = base64(RAND || AUTN || SERV_DATA) */ - n = tsk_base64_decode((const uint8_t*)self->nonce, tsk_strlen(self->nonce), &nonce); - if(n > TSK_MD5_STRING_SIZE){ - TSK_DEBUG_ERROR("The IMS CORE returned an invalid nonce."); - goto bail; - } - if(n < AKA_RAND_SIZE + AKA_AUTN_SIZE){ - TSK_DEBUG_ERROR("The nonce returned by the IMS CORE is too short to contain both [RAND] and [AUTHN]"); - goto bail; - } - else{ - /* Get RAND and AUTN */ - memcpy(RAND, nonce, AKA_RAND_SIZE); - memcpy(AUTN, (nonce + AKA_RAND_SIZE), AKA_AUTN_SIZE); - } - - /* Secret key */ - memcpy(K, password, (tsk_strlen(password) > AKA_K_SIZE ? AKA_K_SIZE : tsk_strlen(password))); - - /* 3GPP TS 35.205: AUTN = SQN[§AK] || AMF || MAC-A */ - memcpy(AMF, (AUTN + AKA_SQN_SIZE), AKA_AMF_SIZE); - memcpy(MAC_A, (AUTN + AKA_SQN_SIZE + AKA_AMF_SIZE), AKA_MAC_A_SIZE); - - /* compute OP */ - ComputeOP(TSIP_CHALLENGE_STACK(self)->security.operator_id); - - /* Checks that we hold the same AMF */ - for(n=0; n<AKA_AMF_SIZE; n++){ - if(AMF[n] != TSIP_CHALLENGE_STACK(self)->security.amf[n]){ - TSK_DEBUG_ERROR("IMS-AKA error: AMF <> XAMF"); - goto bail; - } - } - - /* Calculate CK, IK and AK */ - f2345(K, RAND, akares, CK, IK, AK); - - /* Calculate SQN from SQN_XOR_AK */ - for(n=0; n<AKA_SQN_SIZE; n++){ - SQN[n] = (uint8_t) (SQN_XOR_AK()[n] ^ AK[n]); - } - - /* Calculate XMAC_A */ - { - AKA_MAC_A_T XMAC_A; - memset(XMAC_A, '\0', sizeof(XMAC_A)); - - f1(K, RAND, SQN, AMF, XMAC_A); - if(!tsk_strnequals(MAC_A, XMAC_A, AKA_MAC_A_SIZE)){ - TSK_DEBUG_ERROR("IMS-AKA error: XMAC_A [%s] <> MAC_A[%s]", XMAC_A, MAC_A); - goto bail; - } - } - - /* RFC 4169 subclause 3 - The HTTP Digest password is derived from base64 encoded PRF(RES || IK||CK, "http-digest-akav2-password") - or - PRF(XRES||IK||CK, "http-digest-akav2-password") instead of (RES) or (XRES) respectively. - Where PRF ==> HMAC_MD5 function. - */ - if(TSIP_CHALLENGE_IS_AKAv2(self)){ - uint8_t res_ik_ck[AKA_RES_SIZE + AKA_IK_SIZE + AKA_CK_SIZE]; - tsk_md5digest_t md5_digest; - - memcpy(res_ik_ck, akares, AKA_RES_SIZE); - memcpy((res_ik_ck + AKA_RES_SIZE), IK, AKA_IK_SIZE); - memcpy((res_ik_ck + AKA_RES_SIZE + AKA_IK_SIZE), CK, AKA_CK_SIZE); - - if((ret = hmac_md5digest_compute((const uint8_t*)"http-digest-akav2-password", 26, (const char*)res_ik_ck, sizeof(res_ik_ck), md5_digest))){/* PRF(RES||IK||CK, ...) */ - TSK_DEBUG_ERROR("hmac_md5digest_compute() failed. AKAv2 response will be invalid."); - - ret = -3; - goto bail; - } - else{/* b64(PRF(...)) */ - if(!tsk_base64_encode(md5_digest, sizeof(md5_digest), result)){ - TSK_DEBUG_ERROR("tsk_base64_encode() failed. AKAv2 response will be invalid."); - - ret = -4; - goto bail; - } - } - } - else{ - *result = tsk_calloc(1, AKA_RES_SIZE + 1); - memcpy(*result, akares, AKA_RES_SIZE); - - ret = 0; - } - - /* Copy CK and IK */ - memcpy(self->ck, CK, AKA_CK_SIZE); - memcpy(self->ik, IK, AKA_IK_SIZE); + // § ==> XOR + // || ==> append + + AKA_RES_T akares; + + int ret = -1; + tsk_size_t n; + char *nonce = tsk_null; + + AKA_XXX_DECLARE(RAND); + AKA_XXX_DECLARE(AK); + AKA_XXX_DECLARE(AMF); + AKA_XXX_DECLARE(CK); + AKA_XXX_DECLARE(IK); + AKA_XXX_DECLARE(K); + AKA_XXX_DECLARE(SQN); + AKA_XXX_DECLARE(MAC_A); + AKA_XXX_DECLARE(AUTN); + + AKA_XXX_BZERO(RAND); + AKA_XXX_BZERO(AK); + AKA_XXX_BZERO(AMF); + AKA_XXX_BZERO(CK); + AKA_XXX_BZERO(IK); + AKA_XXX_BZERO(K); + AKA_XXX_BZERO(SQN); + AKA_XXX_BZERO(MAC_A); + AKA_XXX_BZERO(AUTN); + + /* RFC 3310 subclause 3.2: nonce = base64(RAND || AUTN || SERV_DATA) */ + n = tsk_base64_decode((const uint8_t*)self->nonce, tsk_strlen(self->nonce), &nonce); + if(n > TSK_MD5_STRING_SIZE) { + TSK_DEBUG_ERROR("The IMS CORE returned an invalid nonce."); + goto bail; + } + if(n < AKA_RAND_SIZE + AKA_AUTN_SIZE) { + TSK_DEBUG_ERROR("The nonce returned by the IMS CORE is too short to contain both [RAND] and [AUTHN]"); + goto bail; + } + else { + /* Get RAND and AUTN */ + memcpy(RAND, nonce, AKA_RAND_SIZE); + memcpy(AUTN, (nonce + AKA_RAND_SIZE), AKA_AUTN_SIZE); + } + + /* Secret key */ + memcpy(K, password, (tsk_strlen(password) > AKA_K_SIZE ? AKA_K_SIZE : tsk_strlen(password))); + + /* 3GPP TS 35.205: AUTN = SQN[§AK] || AMF || MAC-A */ + memcpy(AMF, (AUTN + AKA_SQN_SIZE), AKA_AMF_SIZE); + memcpy(MAC_A, (AUTN + AKA_SQN_SIZE + AKA_AMF_SIZE), AKA_MAC_A_SIZE); + + /* compute OP */ + ComputeOP(TSIP_CHALLENGE_STACK(self)->security.operator_id); + + /* Checks that we hold the same AMF */ + for(n=0; n<AKA_AMF_SIZE; n++) { + if(AMF[n] != TSIP_CHALLENGE_STACK(self)->security.amf[n]) { + TSK_DEBUG_ERROR("IMS-AKA error: AMF <> XAMF"); + goto bail; + } + } + + /* Calculate CK, IK and AK */ + f2345(K, RAND, akares, CK, IK, AK); + + /* Calculate SQN from SQN_XOR_AK */ + for(n=0; n<AKA_SQN_SIZE; n++) { + SQN[n] = (uint8_t) (SQN_XOR_AK()[n] ^ AK[n]); + } + + /* Calculate XMAC_A */ + { + AKA_MAC_A_T XMAC_A; + memset(XMAC_A, '\0', sizeof(XMAC_A)); + + f1(K, RAND, SQN, AMF, XMAC_A); + if(!tsk_strnequals(MAC_A, XMAC_A, AKA_MAC_A_SIZE)) { + TSK_DEBUG_ERROR("IMS-AKA error: XMAC_A [%s] <> MAC_A[%s]", XMAC_A, MAC_A); + goto bail; + } + } + + /* RFC 4169 subclause 3 + The HTTP Digest password is derived from base64 encoded PRF(RES || IK||CK, "http-digest-akav2-password") + or + PRF(XRES||IK||CK, "http-digest-akav2-password") instead of (RES) or (XRES) respectively. + Where PRF ==> HMAC_MD5 function. + */ + if(TSIP_CHALLENGE_IS_AKAv2(self)) { + uint8_t res_ik_ck[AKA_RES_SIZE + AKA_IK_SIZE + AKA_CK_SIZE]; + tsk_md5digest_t md5_digest; + + memcpy(res_ik_ck, akares, AKA_RES_SIZE); + memcpy((res_ik_ck + AKA_RES_SIZE), IK, AKA_IK_SIZE); + memcpy((res_ik_ck + AKA_RES_SIZE + AKA_IK_SIZE), CK, AKA_CK_SIZE); + + if((ret = hmac_md5digest_compute((const uint8_t*)"http-digest-akav2-password", 26, (const char*)res_ik_ck, sizeof(res_ik_ck), md5_digest))) { /* PRF(RES||IK||CK, ...) */ + TSK_DEBUG_ERROR("hmac_md5digest_compute() failed. AKAv2 response will be invalid."); + + ret = -3; + goto bail; + } + else { /* b64(PRF(...)) */ + if(!tsk_base64_encode(md5_digest, sizeof(md5_digest), result)) { + TSK_DEBUG_ERROR("tsk_base64_encode() failed. AKAv2 response will be invalid."); + + ret = -4; + goto bail; + } + } + } + else { + *result = tsk_calloc(1, AKA_RES_SIZE + 1); + memcpy(*result, akares, AKA_RES_SIZE); + + ret = 0; + } + + /* Copy CK and IK */ + memcpy(self->ck, CK, AKA_CK_SIZE); + memcpy(self->ik, IK, AKA_IK_SIZE); bail: - TSK_FREE(nonce); - return ret; + TSK_FREE(nonce); + return ret; #undef SQN_XOR_AK #undef SERVER_DATA @@ -220,124 +219,124 @@ bail: int tsip_challenge_get_response(tsip_challenge_t *self, const char* method, const char* uristring, const tsk_buffer_t* entity_body, tsk_md5string_t* response) { - if(TSIP_CHALLENGE_IS_DIGEST(self) && self->stack){ - tsk_md5string_t ha1, ha2; - nonce_count_t nc; - - /* === - Calculate HA1 = MD5(A1) = M5(username:realm:secret) - In case of AKAv1-MD5 and AKAv2-MD5 the secret must be computed as per RFC 3310 + 3GPP TS 206/7/8/9. - The resulting AKA RES parameter is treated as a "password"/"secret" when calculating the response directive of RFC 2617. - */ - if(TSIP_CHALLENGE_IS_AKAv1(self) || TSIP_CHALLENGE_IS_AKAv2(self)){ - char* akaresult = tsk_null; - tsip_challenge_get_akares(self, TSIP_CHALLENGE_STACK(self)->identity.password, &akaresult); - if(thttp_auth_digest_HA1(TSIP_CHALLENGE_USERNAME(self), self->realm, akaresult, &ha1)){ - // return -1; - } - TSK_FREE(akaresult); - } - else{ - if(!tsk_strnullORempty(self->ha1_hexstr)){ - // use HA1 provide be the user (e.g. webrtc2sip server will need this to authenticate INVITEs when acting as b2bua) - memset(ha1, 0, sizeof(tsk_md5string_t)); - memcpy(ha1, self->ha1_hexstr, (TSK_MD5_DIGEST_SIZE << 1)); - } - else{ - thttp_auth_digest_HA1(TSIP_CHALLENGE_USERNAME(self), self->realm, TSIP_CHALLENGE_STACK(self)->identity.password, &ha1); - } - } - - /* === - HA2 - */ - thttp_auth_digest_HA2(method, - uristring, - entity_body, - self->qop, - &ha2); - - /* RESPONSE */ - if(self->nc){ - THTTP_NCOUNT_2_STRING(self->nc, nc); - } - thttp_auth_digest_response((const tsk_md5string_t *)&ha1, - self->nonce, - nc, - self->cnonce, - self->qop, - (const tsk_md5string_t *)&ha2, - response); - - if(self->qop){ - self->nc++; - } - - return 0; - } - return -1; + if(TSIP_CHALLENGE_IS_DIGEST(self) && self->stack) { + tsk_md5string_t ha1, ha2; + nonce_count_t nc; + + /* === + Calculate HA1 = MD5(A1) = M5(username:realm:secret) + In case of AKAv1-MD5 and AKAv2-MD5 the secret must be computed as per RFC 3310 + 3GPP TS 206/7/8/9. + The resulting AKA RES parameter is treated as a "password"/"secret" when calculating the response directive of RFC 2617. + */ + if(TSIP_CHALLENGE_IS_AKAv1(self) || TSIP_CHALLENGE_IS_AKAv2(self)) { + char* akaresult = tsk_null; + tsip_challenge_get_akares(self, TSIP_CHALLENGE_STACK(self)->identity.password, &akaresult); + if(thttp_auth_digest_HA1(TSIP_CHALLENGE_USERNAME(self), self->realm, akaresult, &ha1)) { + // return -1; + } + TSK_FREE(akaresult); + } + else { + if(!tsk_strnullORempty(self->ha1_hexstr)) { + // use HA1 provide be the user (e.g. webrtc2sip server will need this to authenticate INVITEs when acting as b2bua) + memset(ha1, 0, sizeof(tsk_md5string_t)); + memcpy(ha1, self->ha1_hexstr, (TSK_MD5_DIGEST_SIZE << 1)); + } + else { + thttp_auth_digest_HA1(TSIP_CHALLENGE_USERNAME(self), self->realm, TSIP_CHALLENGE_STACK(self)->identity.password, &ha1); + } + } + + /* === + HA2 + */ + thttp_auth_digest_HA2(method, + uristring, + entity_body, + self->qop, + &ha2); + + /* RESPONSE */ + if(self->nc) { + THTTP_NCOUNT_2_STRING(self->nc, nc); + } + thttp_auth_digest_response((const tsk_md5string_t *)&ha1, + self->nonce, + nc, + self->cnonce, + self->qop, + (const tsk_md5string_t *)&ha2, + response); + + if(self->qop) { + self->nc++; + } + + return 0; + } + return -1; } int tsip_challenge_update(tsip_challenge_t *self, const char* scheme, const char* realm, const char* nonce, const char* opaque, const char* algorithm, const char* qop) { - if(self){ - int noncechanged = !tsk_striequals(self->nonce, nonce); - - tsk_strupdate(&self->scheme, scheme); - tsk_strupdate(&self->realm, realm); - tsk_strupdate(&self->nonce, nonce); - tsk_strupdate(&self->opaque, opaque); - tsk_strupdate(&self->algorithm, algorithm); - if(qop){ - self->qop = tsk_strcontains(qop, tsk_strlen(qop), "auth-int") ? "auth-int" : - (tsk_strcontains(qop, tsk_strlen(qop), "auth") ? "auth" : tsk_null); - } - - if(noncechanged && self->qop){ - tsip_challenge_reset_cnonce(self); - } - return 0; - } - return -1; + if(self) { + int noncechanged = !tsk_striequals(self->nonce, nonce); + + tsk_strupdate(&self->scheme, scheme); + tsk_strupdate(&self->realm, realm); + tsk_strupdate(&self->nonce, nonce); + tsk_strupdate(&self->opaque, opaque); + tsk_strupdate(&self->algorithm, algorithm); + if(qop) { + self->qop = tsk_strcontains(qop, tsk_strlen(qop), "auth-int") ? "auth-int" : + (tsk_strcontains(qop, tsk_strlen(qop), "auth") ? "auth" : tsk_null); + } + + if(noncechanged && self->qop) { + tsip_challenge_reset_cnonce(self); + } + return 0; + } + return -1; } int tsip_challenge_set_cred(tsip_challenge_t *self, const char* username, const char* ha1_hexstr) { - if(!self || tsk_strlen(ha1_hexstr) != (TSK_MD5_DIGEST_SIZE << 1)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - tsk_strupdate(&self->username, username); - tsk_strupdate(&self->ha1_hexstr, ha1_hexstr); - return 0; + if(!self || tsk_strlen(ha1_hexstr) != (TSK_MD5_DIGEST_SIZE << 1)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_strupdate(&self->username, username); + tsk_strupdate(&self->ha1_hexstr, ha1_hexstr); + return 0; } tsip_header_t *tsip_challenge_create_header_authorization(tsip_challenge_t *self, const tsip_request_t *request) { - tsk_md5string_t response; - nonce_count_t nc; - char *uristring = tsk_null; - tsip_header_t *header = tsk_null; - - if(!self || !self->stack || !request){ - goto bail; - } - - if(!(uristring = tsip_uri_tostring(request->line.request.uri, tsk_true, tsk_false))){ - TSK_DEBUG_ERROR("Failed to parse URI: %s", uristring); - goto bail; - } - - /* We compute the nc here because @ref tsip_challenge_get_response function will increment it's value. */ - if(self->nc){ - THTTP_NCOUNT_2_STRING(self->nc, nc); - } - - /* entity_body ==> request-content */ - if(tsip_challenge_get_response(self, request->line.request.method, uristring, request->Content, &response)){ - goto bail; - } - + tsk_md5string_t response; + nonce_count_t nc; + char *uristring = tsk_null; + tsip_header_t *header = tsk_null; + + if(!self || !self->stack || !request) { + goto bail; + } + + if(!(uristring = tsip_uri_tostring(request->line.request.uri, tsk_true, tsk_false))) { + TSK_DEBUG_ERROR("Failed to parse URI: %s", uristring); + goto bail; + } + + /* We compute the nc here because @ref tsip_challenge_get_response function will increment it's value. */ + if(self->nc) { + THTTP_NCOUNT_2_STRING(self->nc, nc); + } + + /* entity_body ==> request-content */ + if(tsip_challenge_get_response(self, request->line.request.method, uristring, request->Content, &response)) { + goto bail; + } + #define TSIP_AUTH_COPY_VALUES(hdr) \ hdr->username = tsk_strdup(TSIP_CHALLENGE_USERNAME(self)); \ @@ -351,40 +350,40 @@ tsip_header_t *tsip_challenge_create_header_authorization(tsip_challenge_t *self hdr->uri = tsk_strdup(uristring); \ hdr->nc = self->nc? tsk_strdup(nc) : 0; \ hdr->response = tsk_strdup(response); \ - - if(self->isproxy){ - tsip_header_Proxy_Authorization_t *proxy_auth = tsip_header_Proxy_Authorization_create(); - TSIP_AUTH_COPY_VALUES(proxy_auth); - header = TSIP_HEADER(proxy_auth); - } - else{ - tsip_header_Authorization_t *auth = tsip_header_Authorization_create(); - TSIP_AUTH_COPY_VALUES(auth); - header = TSIP_HEADER(auth); - } + + if(self->isproxy) { + tsip_header_Proxy_Authorization_t *proxy_auth = tsip_header_Proxy_Authorization_create(); + TSIP_AUTH_COPY_VALUES(proxy_auth); + header = TSIP_HEADER(proxy_auth); + } + else { + tsip_header_Authorization_t *auth = tsip_header_Authorization_create(); + TSIP_AUTH_COPY_VALUES(auth); + header = TSIP_HEADER(auth); + } bail: - TSK_FREE(uristring); + TSK_FREE(uristring); - return header; + return header; #undef TSIP_AUTH_COPY_VALUES } tsip_header_t *tsip_challenge_create_empty_header_authorization(const char* username, const char* realm, const char* uristring) { - tsip_header_Authorization_t *header = tsip_header_Authorization_create(); - - if(header){ - header->scheme = tsk_strdup("Digest"); - header->username = tsk_strdup(username); - header->realm = tsk_strdup(realm); - header->nonce = tsk_strdup(""); - header->response = tsk_strdup(""); - header->uri = tsk_strdup(uristring); - } - - return TSIP_HEADER(header); + tsip_header_Authorization_t *header = tsip_header_Authorization_create(); + + if(header) { + header->scheme = tsk_strdup("Digest"); + header->username = tsk_strdup(username); + header->realm = tsk_strdup(realm); + header->nonce = tsk_strdup(""); + header->response = tsk_strdup(""); + header->uri = tsk_strdup(uristring); + } + + return TSIP_HEADER(header); } @@ -419,59 +418,60 @@ tsip_header_t *tsip_challenge_create_empty_header_authorization(const char* user */ static tsk_object_t* tsip_challenge_ctor(tsk_object_t *self, va_list * app) { - tsip_challenge_t *challenge = self; - if(challenge){ - const char* qop; - - challenge->stack = va_arg(*app, const tsip_stack_handle_t *); - challenge->isproxy = va_arg(*app, tsk_bool_t); - challenge->username = tsk_strdup(((const struct tsip_stack_s*)challenge->stack)->identity.impi); - challenge->scheme = tsk_strdup(va_arg(*app, const char*)); - challenge->realm = tsk_strdup(va_arg(*app, const char*)); - challenge->nonce = tsk_strdup(va_arg(*app, const char*)); - challenge->opaque = tsk_strdup(va_arg(*app, const char*)); - challenge->algorithm = tsk_strdup(va_arg(*app, const char*)); - qop = va_arg(*app, const char*); - if(qop){ - challenge->qop = tsk_strcontains(qop, tsk_strlen(qop), "auth-int") ? "auth-int" : - (tsk_strcontains(qop, tsk_strlen(qop), "auth") ? "auth" : tsk_null); - } - - if(challenge->qop){ - tsip_challenge_reset_cnonce(challenge); - } - } - else TSK_DEBUG_ERROR("Failed to create new sip challenge object."); - - return self; + tsip_challenge_t *challenge = self; + if(challenge) { + const char* qop; + + challenge->stack = va_arg(*app, const tsip_stack_handle_t *); + challenge->isproxy = va_arg(*app, tsk_bool_t); + challenge->username = tsk_strdup(((const struct tsip_stack_s*)challenge->stack)->identity.impi); + challenge->scheme = tsk_strdup(va_arg(*app, const char*)); + challenge->realm = tsk_strdup(va_arg(*app, const char*)); + challenge->nonce = tsk_strdup(va_arg(*app, const char*)); + challenge->opaque = tsk_strdup(va_arg(*app, const char*)); + challenge->algorithm = tsk_strdup(va_arg(*app, const char*)); + qop = va_arg(*app, const char*); + if(qop) { + challenge->qop = tsk_strcontains(qop, tsk_strlen(qop), "auth-int") ? "auth-int" : + (tsk_strcontains(qop, tsk_strlen(qop), "auth") ? "auth" : tsk_null); + } + + if(challenge->qop) { + tsip_challenge_reset_cnonce(challenge); + } + } + else { + TSK_DEBUG_ERROR("Failed to create new sip challenge object."); + } + + return self; } /**@ingroup tsip_challenge_group */ static tsk_object_t* tsip_challenge_dtor(tsk_object_t *self) { - tsip_challenge_t *challenge = self; - if(challenge){ - TSK_FREE(challenge->username); - TSK_FREE(challenge->scheme); - TSK_FREE(challenge->realm); - TSK_FREE(challenge->nonce); - TSK_FREE(challenge->opaque); - TSK_FREE(challenge->algorithm); - TSK_FREE(challenge->ha1_hexstr); - } - else{ - TSK_DEBUG_ERROR("Null SIP challenge object."); - } - - return self; + tsip_challenge_t *challenge = self; + if(challenge) { + TSK_FREE(challenge->username); + TSK_FREE(challenge->scheme); + TSK_FREE(challenge->realm); + TSK_FREE(challenge->nonce); + TSK_FREE(challenge->opaque); + TSK_FREE(challenge->algorithm); + TSK_FREE(challenge->ha1_hexstr); + } + else { + TSK_DEBUG_ERROR("Null SIP challenge object."); + } + + return self; } -static const tsk_object_def_t tsip_challenge_def_s = -{ - sizeof(tsip_challenge_t), - tsip_challenge_ctor, - tsip_challenge_dtor, - tsk_null +static const tsk_object_def_t tsip_challenge_def_s = { + sizeof(tsip_challenge_t), + tsip_challenge_ctor, + tsip_challenge_dtor, + tsk_null }; const tsk_object_def_t *tsip_challenge_def_t = &tsip_challenge_def_s; diff --git a/tinySIP/src/authentication/tsip_milenage.c b/tinySIP/src/authentication/tsip_milenage.c index 3fd19e2..0c95e4a 100755 --- a/tinySIP/src/authentication/tsip_milenage.c +++ b/tinySIP/src/authentication/tsip_milenage.c @@ -2,19 +2,19 @@ * Partial 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. * @@ -42,7 +42,7 @@ * * This has been coded for clarity, not necessarily for efficiency. * -* The functions f2, f3, f4 and f5 share the same inputs and have +* The functions f2, f3, f4 and f5 share the same inputs and have * been coded together as a single function. f1, f1* and f5* are * all coded separately. * @@ -60,7 +60,8 @@ // 0xff, 0x14, 0xc1, 0xf4, 0x5f, 0x88, 0x73, 0x7d}; /*------- Insert your value of OP here -------*/ uint8_t OP[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; /*------------------------------------------------------------------- * Algorithm f1 @@ -72,58 +73,58 @@ uint8_t OP[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, * *-----------------------------------------------------------------*/ -void f1 ( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], - uint8_t mac_a[8] ) +void f1 ( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], + uint8_t mac_a[8] ) { - uint8_t op_c[16]; - uint8_t temp[16]; - uint8_t in1[16]; - uint8_t out1[16]; - uint8_t rijndaelInput[16]; - uint8_t i; + uint8_t op_c[16]; + uint8_t temp[16]; + uint8_t in1[16]; + uint8_t out1[16]; + uint8_t rijndaelInput[16]; + uint8_t i; - RijndaelKeySchedule( k ); + RijndaelKeySchedule( k ); - ComputeOPc( op_c ); + ComputeOPc( op_c ); - for (i=0; i<16; i++){ - rijndaelInput[i] = rand[i] ^ op_c[i]; - } - RijndaelEncrypt( rijndaelInput, temp ); + for (i=0; i<16; i++) { + rijndaelInput[i] = rand[i] ^ op_c[i]; + } + RijndaelEncrypt( rijndaelInput, temp ); - for (i=0; i<6; i++){ - in1[i] = sqn[i]; - in1[i+8] = sqn[i]; - } + for (i=0; i<6; i++) { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } - for (i=0; i<2; i++){ - in1[i+6] = amf[i]; - in1[i+14] = amf[i]; - } + for (i=0; i<2; i++) { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } - /* XOR op_c and in1, rotate by r1=64, and XOR * - * on the constant c1 (which is all zeroes) */ + /* XOR op_c and in1, rotate by r1=64, and XOR * + * on the constant c1 (which is all zeroes) */ - for (i=0; i<16; i++){ - rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; - } + for (i=0; i<16; i++) { + rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; + } - /* XOR on the value temp computed before */ + /* XOR on the value temp computed before */ - for (i=0; i<16; i++){ - rijndaelInput[i] ^= temp[i]; - } + for (i=0; i<16; i++) { + rijndaelInput[i] ^= temp[i]; + } - RijndaelEncrypt( rijndaelInput, out1 ); - for (i=0; i<16; i++){ - out1[i] ^= op_c[i]; - } + RijndaelEncrypt( rijndaelInput, out1 ); + for (i=0; i<16; i++) { + out1[i] ^= op_c[i]; + } - for (i=0; i<8; i++){ - mac_a[i] = out1[i]; - } + for (i=0; i<8; i++) { + mac_a[i] = out1[i]; + } - return; + return; } /* end of function f1 */ @@ -138,81 +139,81 @@ void f1 ( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], *-----------------------------------------------------------------*/ void f2345 ( uint8_t k[16], uint8_t rand[16], - uint8_t res[8], uint8_t ck[16], uint8_t ik[16], uint8_t ak[6] ) + uint8_t res[8], uint8_t ck[16], uint8_t ik[16], uint8_t ak[6] ) { - uint8_t op_c[16]; - uint8_t temp[16]; - uint8_t out[16]; - uint8_t rijndaelInput[16]; - uint8_t i; - - RijndaelKeySchedule( k ); - - ComputeOPc( op_c ); - - for (i=0; i<16; i++){ - rijndaelInput[i] = rand[i] ^ op_c[i]; - } - RijndaelEncrypt( rijndaelInput, temp ); - - /* To obtain output block OUT2: XOR OPc and TEMP, * - * rotate by r2=0, and XOR on the constant c2 (which * - * is all zeroes except that the last bit is 1). */ - - for (i=0; i<16; i++){ - rijndaelInput[i] = temp[i] ^ op_c[i]; - } - rijndaelInput[15] ^= 1; - - RijndaelEncrypt( rijndaelInput, out ); - for (i=0; i<16; i++){ - out[i] ^= op_c[i]; - } - - for (i=0; i<8; i++){ - res[i] = out[i+8]; - } - for (i=0; i<6; i++){ - ak[i] = out[i]; - } - - /* To obtain output block OUT3: XOR OPc and TEMP, * - * rotate by r3=32, and XOR on the constant c3 (which * - * is all zeroes except that the next to last bit is 1). */ - - for (i=0; i<16; i++){ - rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i]; - } - rijndaelInput[15] ^= 2; - - RijndaelEncrypt( rijndaelInput, out ); - for (i=0; i<16; i++){ - out[i] ^= op_c[i]; - } - - for (i=0; i<16; i++){ - ck[i] = out[i]; - } - - /* To obtain output block OUT4: XOR OPc and TEMP, * - * rotate by r4=64, and XOR on the constant c4 (which * - * is all zeroes except that the 2nd from last bit is 1). */ - - for (i=0; i<16; i++){ - rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i]; - } - rijndaelInput[15] ^= 4; - - RijndaelEncrypt( rijndaelInput, out ); - for (i=0; i<16; i++){ - out[i] ^= op_c[i]; - } - - for (i=0; i<16; i++){ - ik[i] = out[i]; - } - - return; + uint8_t op_c[16]; + uint8_t temp[16]; + uint8_t out[16]; + uint8_t rijndaelInput[16]; + uint8_t i; + + RijndaelKeySchedule( k ); + + ComputeOPc( op_c ); + + for (i=0; i<16; i++) { + rijndaelInput[i] = rand[i] ^ op_c[i]; + } + RijndaelEncrypt( rijndaelInput, temp ); + + /* To obtain output block OUT2: XOR OPc and TEMP, * + * rotate by r2=0, and XOR on the constant c2 (which * + * is all zeroes except that the last bit is 1). */ + + for (i=0; i<16; i++) { + rijndaelInput[i] = temp[i] ^ op_c[i]; + } + rijndaelInput[15] ^= 1; + + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) { + out[i] ^= op_c[i]; + } + + for (i=0; i<8; i++) { + res[i] = out[i+8]; + } + for (i=0; i<6; i++) { + ak[i] = out[i]; + } + + /* To obtain output block OUT3: XOR OPc and TEMP, * + * rotate by r3=32, and XOR on the constant c3 (which * + * is all zeroes except that the next to last bit is 1). */ + + for (i=0; i<16; i++) { + rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i]; + } + rijndaelInput[15] ^= 2; + + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) { + out[i] ^= op_c[i]; + } + + for (i=0; i<16; i++) { + ck[i] = out[i]; + } + + /* To obtain output block OUT4: XOR OPc and TEMP, * + * rotate by r4=64, and XOR on the constant c4 (which * + * is all zeroes except that the 2nd from last bit is 1). */ + + for (i=0; i<16; i++) { + rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i]; + } + rijndaelInput[15] ^= 4; + + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) { + out[i] ^= op_c[i]; + } + + for (i=0; i<16; i++) { + ik[i] = out[i]; + } + + return; } /* end of function f2345 */ @@ -226,57 +227,57 @@ void f2345 ( uint8_t k[16], uint8_t rand[16], * *-----------------------------------------------------------------*/ -void f1star( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], - uint8_t mac_s[8] ) +void f1star( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], + uint8_t mac_s[8] ) { - uint8_t op_c[16]; - uint8_t temp[16]; - uint8_t in1[16]; - uint8_t out1[16]; - uint8_t rijndaelInput[16]; - uint8_t i; - - RijndaelKeySchedule( k ); - - ComputeOPc( op_c ); - - for (i=0; i<16; i++){ - rijndaelInput[i] = rand[i] ^ op_c[i]; - } - RijndaelEncrypt( rijndaelInput, temp ); - - for (i=0; i<6; i++){ - in1[i] = sqn[i]; - in1[i+8] = sqn[i]; - } - for (i=0; i<2; i++){ - in1[i+6] = amf[i]; - in1[i+14] = amf[i]; - } - - /* XOR op_c and in1, rotate by r1=64, and XOR * - * on the constant c1 (which is all zeroes) */ - - for (i=0; i<16; i++){ - rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; - } - - /* XOR on the value temp computed before */ - - for (i=0; i<16; i++){ - rijndaelInput[i] ^= temp[i]; - } - - RijndaelEncrypt( rijndaelInput, out1 ); - for (i=0; i<16; i++){ - out1[i] ^= op_c[i]; - } - - for (i=0; i<8; i++){ - mac_s[i] = out1[i+8]; - } - - return; + uint8_t op_c[16]; + uint8_t temp[16]; + uint8_t in1[16]; + uint8_t out1[16]; + uint8_t rijndaelInput[16]; + uint8_t i; + + RijndaelKeySchedule( k ); + + ComputeOPc( op_c ); + + for (i=0; i<16; i++) { + rijndaelInput[i] = rand[i] ^ op_c[i]; + } + RijndaelEncrypt( rijndaelInput, temp ); + + for (i=0; i<6; i++) { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } + for (i=0; i<2; i++) { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } + + /* XOR op_c and in1, rotate by r1=64, and XOR * + * on the constant c1 (which is all zeroes) */ + + for (i=0; i<16; i++) { + rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; + } + + /* XOR on the value temp computed before */ + + for (i=0; i<16; i++) { + rijndaelInput[i] ^= temp[i]; + } + + RijndaelEncrypt( rijndaelInput, out1 ); + for (i=0; i<16; i++) { + out1[i] ^= op_c[i]; + } + + for (i=0; i<8; i++) { + mac_s[i] = out1[i+8]; + } + + return; } /* end of function f1star */ @@ -290,38 +291,42 @@ void f1star( uint8_t k[16], uint8_t rand[16], uint8_t sqn[6], uint8_t amf[2], *-----------------------------------------------------------------*/ void f5star( uint8_t k[16], uint8_t rand[16], - uint8_t ak[6] ) + uint8_t ak[6] ) { - uint8_t op_c[16]; - uint8_t temp[16]; - uint8_t out[16]; - uint8_t rijndaelInput[16]; - uint8_t i; + uint8_t op_c[16]; + uint8_t temp[16]; + uint8_t out[16]; + uint8_t rijndaelInput[16]; + uint8_t i; - RijndaelKeySchedule( k ); + RijndaelKeySchedule( k ); - ComputeOPc( op_c ); + ComputeOPc( op_c ); - for (i=0; i<16; i++) - rijndaelInput[i] = rand[i] ^ op_c[i]; - RijndaelEncrypt( rijndaelInput, temp ); + for (i=0; i<16; i++) { + rijndaelInput[i] = rand[i] ^ op_c[i]; + } + RijndaelEncrypt( rijndaelInput, temp ); - /* To obtain output block OUT5: XOR OPc and TEMP, * - * rotate by r5=96, and XOR on the constant c5 (which * - * is all zeroes except that the 3rd from last bit is 1). */ + /* To obtain output block OUT5: XOR OPc and TEMP, * + * rotate by r5=96, and XOR on the constant c5 (which * + * is all zeroes except that the 3rd from last bit is 1). */ - for (i=0; i<16; i++) - rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i]; - rijndaelInput[15] ^= 8; + for (i=0; i<16; i++) { + rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i]; + } + rijndaelInput[15] ^= 8; - RijndaelEncrypt( rijndaelInput, out ); - for (i=0; i<16; i++) - out[i] ^= op_c[i]; + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) { + out[i] ^= op_c[i]; + } - for (i=0; i<6; i++) - ak[i] = out[i]; + for (i=0; i<6; i++) { + ak[i] = out[i]; + } - return; + return; } /* end of function f5star */ @@ -332,19 +337,20 @@ already been performed. void ComputeOPc( uint8_t op_c[16] ) { - uint8_t i; + uint8_t i; - RijndaelEncrypt( OP, op_c ); - for (i=0; i<16; i++){ - op_c[i] ^= OP[i]; - } + RijndaelEncrypt( OP, op_c ); + for (i=0; i<16; i++) { + op_c[i] ^= OP[i]; + } - return; + return; } /* end of function ComputeOPc */ -void ComputeOP( uint8_t op[16] ){ - int i; - for(i=0;i<16;i++){ - OP[i]=op[i]; - } +void ComputeOP( uint8_t op[16] ) +{ + int i; + for(i=0; i<16; i++) { + OP[i]=op[i]; + } } diff --git a/tinySIP/src/authentication/tsip_rijndael.c b/tinySIP/src/authentication/tsip_rijndael.c index ddcd89f..c0cddff 100755 --- a/tinySIP/src/authentication/tsip_rijndael.c +++ b/tinySIP/src/authentication/tsip_rijndael.c @@ -2,19 +2,19 @@ * Partial 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. * @@ -79,316 +79,316 @@ #elif defined(__GNUC__) && !defined(__APPLE__) # define __INLINE __inline #else -# define __INLINE +# define __INLINE #endif -__INLINE uint32_t byte_swap(uint32_t x){ +__INLINE uint32_t byte_swap(uint32_t x) +{ return rot1(x) & 0x00ff00ff | rot3(x) & 0xff00ff00; } -__INLINE uint32_t u32_in(const uint8_t x[]){ - if(tnet_is_BE()){ - return byte_swap(*(uint32_t*)x); - } - else{ - return (*(uint32_t*)(x)); - } +__INLINE uint32_t u32_in(const uint8_t x[]) +{ + if(tnet_is_BE()) { + return byte_swap(*(uint32_t*)x); + } + else { + return (*(uint32_t*)(x)); + } } -__INLINE void u32_out(uint8_t x[], const uint32_t v){ - if(tnet_is_BE()){ - *(uint32_t*)x = byte_swap(v); - } - else{ - (*(uint32_t*)(x) = v); - } +__INLINE void u32_out(uint8_t x[], const uint32_t v) +{ + if(tnet_is_BE()) { + *(uint32_t*)x = byte_swap(v); + } + else { + (*(uint32_t*)(x) = v); + } } /*--------------- The lookup tables ----------------------------*/ -static uint32_t rnd_con[10] = -{ - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 +static uint32_t rnd_con[10] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }; -static uint32_t ft_tab[4][256] = -{ - { - 0xA56363C6,0x847C7CF8,0x997777EE,0x8D7B7BF6,0x0DF2F2FF,0xBD6B6BD6,0xB16F6FDE,0x54C5C591, - 0x50303060,0x03010102,0xA96767CE,0x7D2B2B56,0x19FEFEE7,0x62D7D7B5,0xE6ABAB4D,0x9A7676EC, - 0x45CACA8F,0x9D82821F,0x40C9C989,0x877D7DFA,0x15FAFAEF,0xEB5959B2,0xC947478E,0x0BF0F0FB, - 0xECADAD41,0x67D4D4B3,0xFDA2A25F,0xEAAFAF45,0xBF9C9C23,0xF7A4A453,0x967272E4,0x5BC0C09B, - 0xC2B7B775,0x1CFDFDE1,0xAE93933D,0x6A26264C,0x5A36366C,0x413F3F7E,0x02F7F7F5,0x4FCCCC83, - 0x5C343468,0xF4A5A551,0x34E5E5D1,0x08F1F1F9,0x937171E2,0x73D8D8AB,0x53313162,0x3F15152A, - 0x0C040408,0x52C7C795,0x65232346,0x5EC3C39D,0x28181830,0xA1969637,0x0F05050A,0xB59A9A2F, - 0x0907070E,0x36121224,0x9B80801B,0x3DE2E2DF,0x26EBEBCD,0x6927274E,0xCDB2B27F,0x9F7575EA, - 0x1B090912,0x9E83831D,0x742C2C58,0x2E1A1A34,0x2D1B1B36,0xB26E6EDC,0xEE5A5AB4,0xFBA0A05B, - 0xF65252A4,0x4D3B3B76,0x61D6D6B7,0xCEB3B37D,0x7B292952,0x3EE3E3DD,0x712F2F5E,0x97848413, - 0xF55353A6,0x68D1D1B9,0000000000,0x2CEDEDC1,0x60202040,0x1FFCFCE3,0xC8B1B179,0xED5B5BB6, - 0xBE6A6AD4,0x46CBCB8D,0xD9BEBE67,0x4B393972,0xDE4A4A94,0xD44C4C98,0xE85858B0,0x4ACFCF85, - 0x6BD0D0BB,0x2AEFEFC5,0xE5AAAA4F,0x16FBFBED,0xC5434386,0xD74D4D9A,0x55333366,0x94858511, - 0xCF45458A,0x10F9F9E9,0x06020204,0x817F7FFE,0xF05050A0,0x443C3C78,0xBA9F9F25,0xE3A8A84B, - 0xF35151A2,0xFEA3A35D,0xC0404080,0x8A8F8F05,0xAD92923F,0xBC9D9D21,0x48383870,0x04F5F5F1, - 0xDFBCBC63,0xC1B6B677,0x75DADAAF,0x63212142,0x30101020,0x1AFFFFE5,0x0EF3F3FD,0x6DD2D2BF, - 0x4CCDCD81,0x140C0C18,0x35131326,0x2FECECC3,0xE15F5FBE,0xA2979735,0xCC444488,0x3917172E, - 0x57C4C493,0xF2A7A755,0x827E7EFC,0x473D3D7A,0xAC6464C8,0xE75D5DBA,0x2B191932,0x957373E6, - 0xA06060C0,0x98818119,0xD14F4F9E,0x7FDCDCA3,0x66222244,0x7E2A2A54,0xAB90903B,0x8388880B, - 0xCA46468C,0x29EEEEC7,0xD3B8B86B,0x3C141428,0x79DEDEA7,0xE25E5EBC,0x1D0B0B16,0x76DBDBAD, - 0x3BE0E0DB,0x56323264,0x4E3A3A74,0x1E0A0A14,0xDB494992,0x0A06060C,0x6C242448,0xE45C5CB8, - 0x5DC2C29F,0x6ED3D3BD,0xEFACAC43,0xA66262C4,0xA8919139,0xA4959531,0x37E4E4D3,0x8B7979F2, - 0x32E7E7D5,0x43C8C88B,0x5937376E,0xB76D6DDA,0x8C8D8D01,0x64D5D5B1,0xD24E4E9C,0xE0A9A949, - 0xB46C6CD8,0xFA5656AC,0x07F4F4F3,0x25EAEACF,0xAF6565CA,0x8E7A7AF4,0xE9AEAE47,0x18080810, - 0xD5BABA6F,0x887878F0,0x6F25254A,0x722E2E5C,0x241C1C38,0xF1A6A657,0xC7B4B473,0x51C6C697, - 0x23E8E8CB,0x7CDDDDA1,0x9C7474E8,0x211F1F3E,0xDD4B4B96,0xDCBDBD61,0x868B8B0D,0x858A8A0F, - 0x907070E0,0x423E3E7C,0xC4B5B571,0xAA6666CC,0xD8484890,0x05030306,0x01F6F6F7,0x120E0E1C, - 0xA36161C2,0x5F35356A,0xF95757AE,0xD0B9B969,0x91868617,0x58C1C199,0x271D1D3A,0xB99E9E27, - 0x38E1E1D9,0x13F8F8EB,0xB398982B,0x33111122,0xBB6969D2,0x70D9D9A9,0x898E8E07,0xA7949433, - 0xB69B9B2D,0x221E1E3C,0x92878715,0x20E9E9C9,0x49CECE87,0xFF5555AA,0x78282850,0x7ADFDFA5, - 0x8F8C8C03,0xF8A1A159,0x80898909,0x170D0D1A,0xDABFBF65,0x31E6E6D7,0xC6424284,0xB86868D0, - 0xC3414182,0xB0999929,0x772D2D5A,0x110F0F1E,0xCBB0B07B,0xFC5454A8,0xD6BBBB6D,0x3A16162C - }, - { - 0x6363C6A5,0x7C7CF884,0x7777EE99,0x7B7BF68D,0xF2F2FF0D,0x6B6BD6BD,0x6F6FDEB1,0xC5C59154, - 0x30306050,0x01010203,0x6767CEA9,0x2B2B567D,0xFEFEE719,0xD7D7B562,0xABAB4DE6,0x7676EC9A, - 0xCACA8F45,0x82821F9D,0xC9C98940,0x7D7DFA87,0xFAFAEF15,0x5959B2EB,0x47478EC9,0xF0F0FB0B, - 0xADAD41EC,0xD4D4B367,0xA2A25FFD,0xAFAF45EA,0x9C9C23BF,0xA4A453F7,0x7272E496,0xC0C09B5B, - 0xB7B775C2,0xFDFDE11C,0x93933DAE,0x26264C6A,0x36366C5A,0x3F3F7E41,0xF7F7F502,0xCCCC834F, - 0x3434685C,0xA5A551F4,0xE5E5D134,0xF1F1F908,0x7171E293,0xD8D8AB73,0x31316253,0x15152A3F, - 0x0404080C,0xC7C79552,0x23234665,0xC3C39D5E,0x18183028,0x969637A1,0x05050A0F,0x9A9A2FB5, - 0x07070E09,0x12122436,0x80801B9B,0xE2E2DF3D,0xEBEBCD26,0x27274E69,0xB2B27FCD,0x7575EA9F, - 0x0909121B,0x83831D9E,0x2C2C5874,0x1A1A342E,0x1B1B362D,0x6E6EDCB2,0x5A5AB4EE,0xA0A05BFB, - 0x5252A4F6,0x3B3B764D,0xD6D6B761,0xB3B37DCE,0x2929527B,0xE3E3DD3E,0x2F2F5E71,0x84841397, - 0x5353A6F5,0xD1D1B968,0000000000,0xEDEDC12C,0x20204060,0xFCFCE31F,0xB1B179C8,0x5B5BB6ED, - 0x6A6AD4BE,0xCBCB8D46,0xBEBE67D9,0x3939724B,0x4A4A94DE,0x4C4C98D4,0x5858B0E8,0xCFCF854A, - 0xD0D0BB6B,0xEFEFC52A,0xAAAA4FE5,0xFBFBED16,0x434386C5,0x4D4D9AD7,0x33336655,0x85851194, - 0x45458ACF,0xF9F9E910,0x02020406,0x7F7FFE81,0x5050A0F0,0x3C3C7844,0x9F9F25BA,0xA8A84BE3, - 0x5151A2F3,0xA3A35DFE,0x404080C0,0x8F8F058A,0x92923FAD,0x9D9D21BC,0x38387048,0xF5F5F104, - 0xBCBC63DF,0xB6B677C1,0xDADAAF75,0x21214263,0x10102030,0xFFFFE51A,0xF3F3FD0E,0xD2D2BF6D, - 0xCDCD814C,0x0C0C1814,0x13132635,0xECECC32F,0x5F5FBEE1,0x979735A2,0x444488CC,0x17172E39, - 0xC4C49357,0xA7A755F2,0x7E7EFC82,0x3D3D7A47,0x6464C8AC,0x5D5DBAE7,0x1919322B,0x7373E695, - 0x6060C0A0,0x81811998,0x4F4F9ED1,0xDCDCA37F,0x22224466,0x2A2A547E,0x90903BAB,0x88880B83, - 0x46468CCA,0xEEEEC729,0xB8B86BD3,0x1414283C,0xDEDEA779,0x5E5EBCE2,0x0B0B161D,0xDBDBAD76, - 0xE0E0DB3B,0x32326456,0x3A3A744E,0x0A0A141E,0x494992DB,0x06060C0A,0x2424486C,0x5C5CB8E4, - 0xC2C29F5D,0xD3D3BD6E,0xACAC43EF,0x6262C4A6,0x919139A8,0x959531A4,0xE4E4D337,0x7979F28B, - 0xE7E7D532,0xC8C88B43,0x37376E59,0x6D6DDAB7,0x8D8D018C,0xD5D5B164,0x4E4E9CD2,0xA9A949E0, - 0x6C6CD8B4,0x5656ACFA,0xF4F4F307,0xEAEACF25,0x6565CAAF,0x7A7AF48E,0xAEAE47E9,0x08081018, - 0xBABA6FD5,0x7878F088,0x25254A6F,0x2E2E5C72,0x1C1C3824,0xA6A657F1,0xB4B473C7,0xC6C69751, - 0xE8E8CB23,0xDDDDA17C,0x7474E89C,0x1F1F3E21,0x4B4B96DD,0xBDBD61DC,0x8B8B0D86,0x8A8A0F85, - 0x7070E090,0x3E3E7C42,0xB5B571C4,0x6666CCAA,0x484890D8,0x03030605,0xF6F6F701,0x0E0E1C12, - 0x6161C2A3,0x35356A5F,0x5757AEF9,0xB9B969D0,0x86861791,0xC1C19958,0x1D1D3A27,0x9E9E27B9, - 0xE1E1D938,0xF8F8EB13,0x98982BB3,0x11112233,0x6969D2BB,0xD9D9A970,0x8E8E0789,0x949433A7, - 0x9B9B2DB6,0x1E1E3C22,0x87871592,0xE9E9C920,0xCECE8749,0x5555AAFF,0x28285078,0xDFDFA57A, - 0x8C8C038F,0xA1A159F8,0x89890980,0x0D0D1A17,0xBFBF65DA,0xE6E6D731,0x424284C6,0x6868D0B8, - 0x414182C3,0x999929B0,0x2D2D5A77,0x0F0F1E11,0xB0B07BCB,0x5454A8FC,0xBBBB6DD6,0x16162C3A - }, - { - 0x63C6A563,0x7CF8847C,0x77EE9977,0x7BF68D7B,0xF2FF0DF2,0x6BD6BD6B,0x6FDEB16F,0xC59154C5, - 0x30605030,0x01020301,0x67CEA967,0x2B567D2B,0xFEE719FE,0xD7B562D7,0xAB4DE6AB,0x76EC9A76, - 0xCA8F45CA,0x821F9D82,0xC98940C9,0x7DFA877D,0xFAEF15FA,0x59B2EB59,0x478EC947,0xF0FB0BF0, - 0xAD41ECAD,0xD4B367D4,0xA25FFDA2,0xAF45EAAF,0x9C23BF9C,0xA453F7A4,0x72E49672,0xC09B5BC0, - 0xB775C2B7,0xFDE11CFD,0x933DAE93,0x264C6A26,0x366C5A36,0x3F7E413F,0xF7F502F7,0xCC834FCC, - 0x34685C34,0xA551F4A5,0xE5D134E5,0xF1F908F1,0x71E29371,0xD8AB73D8,0x31625331,0x152A3F15, - 0x04080C04,0xC79552C7,0x23466523,0xC39D5EC3,0x18302818,0x9637A196,0x050A0F05,0x9A2FB59A, - 0x070E0907,0x12243612,0x801B9B80,0xE2DF3DE2,0xEBCD26EB,0x274E6927,0xB27FCDB2,0x75EA9F75, - 0x09121B09,0x831D9E83,0x2C58742C,0x1A342E1A,0x1B362D1B,0x6EDCB26E,0x5AB4EE5A,0xA05BFBA0, - 0x52A4F652,0x3B764D3B,0xD6B761D6,0xB37DCEB3,0x29527B29,0xE3DD3EE3,0x2F5E712F,0x84139784, - 0x53A6F553,0xD1B968D1,0000000000,0xEDC12CED,0x20406020,0xFCE31FFC,0xB179C8B1,0x5BB6ED5B, - 0x6AD4BE6A,0xCB8D46CB,0xBE67D9BE,0x39724B39,0x4A94DE4A,0x4C98D44C,0x58B0E858,0xCF854ACF, - 0xD0BB6BD0,0xEFC52AEF,0xAA4FE5AA,0xFBED16FB,0x4386C543,0x4D9AD74D,0x33665533,0x85119485, - 0x458ACF45,0xF9E910F9,0x02040602,0x7FFE817F,0x50A0F050,0x3C78443C,0x9F25BA9F,0xA84BE3A8, - 0x51A2F351,0xA35DFEA3,0x4080C040,0x8F058A8F,0x923FAD92,0x9D21BC9D,0x38704838,0xF5F104F5, - 0xBC63DFBC,0xB677C1B6,0xDAAF75DA,0x21426321,0x10203010,0xFFE51AFF,0xF3FD0EF3,0xD2BF6DD2, - 0xCD814CCD,0x0C18140C,0x13263513,0xECC32FEC,0x5FBEE15F,0x9735A297,0x4488CC44,0x172E3917, - 0xC49357C4,0xA755F2A7,0x7EFC827E,0x3D7A473D,0x64C8AC64,0x5DBAE75D,0x19322B19,0x73E69573, - 0x60C0A060,0x81199881,0x4F9ED14F,0xDCA37FDC,0x22446622,0x2A547E2A,0x903BAB90,0x880B8388, - 0x468CCA46,0xEEC729EE,0xB86BD3B8,0x14283C14,0xDEA779DE,0x5EBCE25E,0x0B161D0B,0xDBAD76DB, - 0xE0DB3BE0,0x32645632,0x3A744E3A,0x0A141E0A,0x4992DB49,0x060C0A06,0x24486C24,0x5CB8E45C, - 0xC29F5DC2,0xD3BD6ED3,0xAC43EFAC,0x62C4A662,0x9139A891,0x9531A495,0xE4D337E4,0x79F28B79, - 0xE7D532E7,0xC88B43C8,0x376E5937,0x6DDAB76D,0x8D018C8D,0xD5B164D5,0x4E9CD24E,0xA949E0A9, - 0x6CD8B46C,0x56ACFA56,0xF4F307F4,0xEACF25EA,0x65CAAF65,0x7AF48E7A,0xAE47E9AE,0x08101808, - 0xBA6FD5BA,0x78F08878,0x254A6F25,0x2E5C722E,0x1C38241C,0xA657F1A6,0xB473C7B4,0xC69751C6, - 0xE8CB23E8,0xDDA17CDD,0x74E89C74,0x1F3E211F,0x4B96DD4B,0xBD61DCBD,0x8B0D868B,0x8A0F858A, - 0x70E09070,0x3E7C423E,0xB571C4B5,0x66CCAA66,0x4890D848,0x03060503,0xF6F701F6,0x0E1C120E, - 0x61C2A361,0x356A5F35,0x57AEF957,0xB969D0B9,0x86179186,0xC19958C1,0x1D3A271D,0x9E27B99E, - 0xE1D938E1,0xF8EB13F8,0x982BB398,0x11223311,0x69D2BB69,0xD9A970D9,0x8E07898E,0x9433A794, - 0x9B2DB69B,0x1E3C221E,0x87159287,0xE9C920E9,0xCE8749CE,0x55AAFF55,0x28507828,0xDFA57ADF, - 0x8C038F8C,0xA159F8A1,0x89098089,0x0D1A170D,0xBF65DABF,0xE6D731E6,0x4284C642,0x68D0B868, - 0x4182C341,0x9929B099,0x2D5A772D,0x0F1E110F,0xB07BCBB0,0x54A8FC54,0xBB6DD6BB,0x162C3A16 - }, - { - 0xC6A56363,0xF8847C7C,0xEE997777,0xF68D7B7B,0xFF0DF2F2,0xD6BD6B6B,0xDEB16F6F,0x9154C5C5, - 0x60503030,0x02030101,0xCEA96767,0x567D2B2B,0xE719FEFE,0xB562D7D7,0x4DE6ABAB,0xEC9A7676, - 0x8F45CACA,0x1F9D8282,0x8940C9C9,0xFA877D7D,0xEF15FAFA,0xB2EB5959,0x8EC94747,0xFB0BF0F0, - 0x41ECADAD,0xB367D4D4,0x5FFDA2A2,0x45EAAFAF,0x23BF9C9C,0x53F7A4A4,0xE4967272,0x9B5BC0C0, - 0x75C2B7B7,0xE11CFDFD,0x3DAE9393,0x4C6A2626,0x6C5A3636,0x7E413F3F,0xF502F7F7,0x834FCCCC, - 0x685C3434,0x51F4A5A5,0xD134E5E5,0xF908F1F1,0xE2937171,0xAB73D8D8,0x62533131,0x2A3F1515, - 0x080C0404,0x9552C7C7,0x46652323,0x9D5EC3C3,0x30281818,0x37A19696,0x0A0F0505,0x2FB59A9A, - 0x0E090707,0x24361212,0x1B9B8080,0xDF3DE2E2,0xCD26EBEB,0x4E692727,0x7FCDB2B2,0xEA9F7575, - 0x121B0909,0x1D9E8383,0x58742C2C,0x342E1A1A,0x362D1B1B,0xDCB26E6E,0xB4EE5A5A,0x5BFBA0A0, - 0xA4F65252,0x764D3B3B,0xB761D6D6,0x7DCEB3B3,0x527B2929,0xDD3EE3E3,0x5E712F2F,0x13978484, - 0xA6F55353,0xB968D1D1,0000000000,0xC12CEDED,0x40602020,0xE31FFCFC,0x79C8B1B1,0xB6ED5B5B, - 0xD4BE6A6A,0x8D46CBCB,0x67D9BEBE,0x724B3939,0x94DE4A4A,0x98D44C4C,0xB0E85858,0x854ACFCF, - 0xBB6BD0D0,0xC52AEFEF,0x4FE5AAAA,0xED16FBFB,0x86C54343,0x9AD74D4D,0x66553333,0x11948585, - 0x8ACF4545,0xE910F9F9,0x04060202,0xFE817F7F,0xA0F05050,0x78443C3C,0x25BA9F9F,0x4BE3A8A8, - 0xA2F35151,0x5DFEA3A3,0x80C04040,0x058A8F8F,0x3FAD9292,0x21BC9D9D,0x70483838,0xF104F5F5, - 0x63DFBCBC,0x77C1B6B6,0xAF75DADA,0x42632121,0x20301010,0xE51AFFFF,0xFD0EF3F3,0xBF6DD2D2, - 0x814CCDCD,0x18140C0C,0x26351313,0xC32FECEC,0xBEE15F5F,0x35A29797,0x88CC4444,0x2E391717, - 0x9357C4C4,0x55F2A7A7,0xFC827E7E,0x7A473D3D,0xC8AC6464,0xBAE75D5D,0x322B1919,0xE6957373, - 0xC0A06060,0x19988181,0x9ED14F4F,0xA37FDCDC,0x44662222,0x547E2A2A,0x3BAB9090,0x0B838888, - 0x8CCA4646,0xC729EEEE,0x6BD3B8B8,0x283C1414,0xA779DEDE,0xBCE25E5E,0x161D0B0B,0xAD76DBDB, - 0xDB3BE0E0,0x64563232,0x744E3A3A,0x141E0A0A,0x92DB4949,0x0C0A0606,0x486C2424,0xB8E45C5C, - 0x9F5DC2C2,0xBD6ED3D3,0x43EFACAC,0xC4A66262,0x39A89191,0x31A49595,0xD337E4E4,0xF28B7979, - 0xD532E7E7,0x8B43C8C8,0x6E593737,0xDAB76D6D,0x018C8D8D,0xB164D5D5,0x9CD24E4E,0x49E0A9A9, - 0xD8B46C6C,0xACFA5656,0xF307F4F4,0xCF25EAEA,0xCAAF6565,0xF48E7A7A,0x47E9AEAE,0x10180808, - 0x6FD5BABA,0xF0887878,0x4A6F2525,0x5C722E2E,0x38241C1C,0x57F1A6A6,0x73C7B4B4,0x9751C6C6, - 0xCB23E8E8,0xA17CDDDD,0xE89C7474,0x3E211F1F,0x96DD4B4B,0x61DCBDBD,0x0D868B8B,0x0F858A8A, - 0xE0907070,0x7C423E3E,0x71C4B5B5,0xCCAA6666,0x90D84848,0x06050303,0xF701F6F6,0x1C120E0E, - 0xC2A36161,0x6A5F3535,0xAEF95757,0x69D0B9B9,0x17918686,0x9958C1C1,0x3A271D1D,0x27B99E9E, - 0xD938E1E1,0xEB13F8F8,0x2BB39898,0x22331111,0xD2BB6969,0xA970D9D9,0x07898E8E,0x33A79494, - 0x2DB69B9B,0x3C221E1E,0x15928787,0xC920E9E9,0x8749CECE,0xAAFF5555,0x50782828,0xA57ADFDF, - 0x038F8C8C,0x59F8A1A1,0x09808989,0x1A170D0D,0x65DABFBF,0xD731E6E6,0x84C64242,0xD0B86868, - 0x82C34141,0x29B09999,0x5A772D2D,0x1E110F0F,0x7BCBB0B0,0xA8FC5454,0x6DD6BBBB,0x2C3A1616 - } +static uint32_t ft_tab[4][256] = { + { + 0xA56363C6,0x847C7CF8,0x997777EE,0x8D7B7BF6,0x0DF2F2FF,0xBD6B6BD6,0xB16F6FDE,0x54C5C591, + 0x50303060,0x03010102,0xA96767CE,0x7D2B2B56,0x19FEFEE7,0x62D7D7B5,0xE6ABAB4D,0x9A7676EC, + 0x45CACA8F,0x9D82821F,0x40C9C989,0x877D7DFA,0x15FAFAEF,0xEB5959B2,0xC947478E,0x0BF0F0FB, + 0xECADAD41,0x67D4D4B3,0xFDA2A25F,0xEAAFAF45,0xBF9C9C23,0xF7A4A453,0x967272E4,0x5BC0C09B, + 0xC2B7B775,0x1CFDFDE1,0xAE93933D,0x6A26264C,0x5A36366C,0x413F3F7E,0x02F7F7F5,0x4FCCCC83, + 0x5C343468,0xF4A5A551,0x34E5E5D1,0x08F1F1F9,0x937171E2,0x73D8D8AB,0x53313162,0x3F15152A, + 0x0C040408,0x52C7C795,0x65232346,0x5EC3C39D,0x28181830,0xA1969637,0x0F05050A,0xB59A9A2F, + 0x0907070E,0x36121224,0x9B80801B,0x3DE2E2DF,0x26EBEBCD,0x6927274E,0xCDB2B27F,0x9F7575EA, + 0x1B090912,0x9E83831D,0x742C2C58,0x2E1A1A34,0x2D1B1B36,0xB26E6EDC,0xEE5A5AB4,0xFBA0A05B, + 0xF65252A4,0x4D3B3B76,0x61D6D6B7,0xCEB3B37D,0x7B292952,0x3EE3E3DD,0x712F2F5E,0x97848413, + 0xF55353A6,0x68D1D1B9,0000000000,0x2CEDEDC1,0x60202040,0x1FFCFCE3,0xC8B1B179,0xED5B5BB6, + 0xBE6A6AD4,0x46CBCB8D,0xD9BEBE67,0x4B393972,0xDE4A4A94,0xD44C4C98,0xE85858B0,0x4ACFCF85, + 0x6BD0D0BB,0x2AEFEFC5,0xE5AAAA4F,0x16FBFBED,0xC5434386,0xD74D4D9A,0x55333366,0x94858511, + 0xCF45458A,0x10F9F9E9,0x06020204,0x817F7FFE,0xF05050A0,0x443C3C78,0xBA9F9F25,0xE3A8A84B, + 0xF35151A2,0xFEA3A35D,0xC0404080,0x8A8F8F05,0xAD92923F,0xBC9D9D21,0x48383870,0x04F5F5F1, + 0xDFBCBC63,0xC1B6B677,0x75DADAAF,0x63212142,0x30101020,0x1AFFFFE5,0x0EF3F3FD,0x6DD2D2BF, + 0x4CCDCD81,0x140C0C18,0x35131326,0x2FECECC3,0xE15F5FBE,0xA2979735,0xCC444488,0x3917172E, + 0x57C4C493,0xF2A7A755,0x827E7EFC,0x473D3D7A,0xAC6464C8,0xE75D5DBA,0x2B191932,0x957373E6, + 0xA06060C0,0x98818119,0xD14F4F9E,0x7FDCDCA3,0x66222244,0x7E2A2A54,0xAB90903B,0x8388880B, + 0xCA46468C,0x29EEEEC7,0xD3B8B86B,0x3C141428,0x79DEDEA7,0xE25E5EBC,0x1D0B0B16,0x76DBDBAD, + 0x3BE0E0DB,0x56323264,0x4E3A3A74,0x1E0A0A14,0xDB494992,0x0A06060C,0x6C242448,0xE45C5CB8, + 0x5DC2C29F,0x6ED3D3BD,0xEFACAC43,0xA66262C4,0xA8919139,0xA4959531,0x37E4E4D3,0x8B7979F2, + 0x32E7E7D5,0x43C8C88B,0x5937376E,0xB76D6DDA,0x8C8D8D01,0x64D5D5B1,0xD24E4E9C,0xE0A9A949, + 0xB46C6CD8,0xFA5656AC,0x07F4F4F3,0x25EAEACF,0xAF6565CA,0x8E7A7AF4,0xE9AEAE47,0x18080810, + 0xD5BABA6F,0x887878F0,0x6F25254A,0x722E2E5C,0x241C1C38,0xF1A6A657,0xC7B4B473,0x51C6C697, + 0x23E8E8CB,0x7CDDDDA1,0x9C7474E8,0x211F1F3E,0xDD4B4B96,0xDCBDBD61,0x868B8B0D,0x858A8A0F, + 0x907070E0,0x423E3E7C,0xC4B5B571,0xAA6666CC,0xD8484890,0x05030306,0x01F6F6F7,0x120E0E1C, + 0xA36161C2,0x5F35356A,0xF95757AE,0xD0B9B969,0x91868617,0x58C1C199,0x271D1D3A,0xB99E9E27, + 0x38E1E1D9,0x13F8F8EB,0xB398982B,0x33111122,0xBB6969D2,0x70D9D9A9,0x898E8E07,0xA7949433, + 0xB69B9B2D,0x221E1E3C,0x92878715,0x20E9E9C9,0x49CECE87,0xFF5555AA,0x78282850,0x7ADFDFA5, + 0x8F8C8C03,0xF8A1A159,0x80898909,0x170D0D1A,0xDABFBF65,0x31E6E6D7,0xC6424284,0xB86868D0, + 0xC3414182,0xB0999929,0x772D2D5A,0x110F0F1E,0xCBB0B07B,0xFC5454A8,0xD6BBBB6D,0x3A16162C + }, + { + 0x6363C6A5,0x7C7CF884,0x7777EE99,0x7B7BF68D,0xF2F2FF0D,0x6B6BD6BD,0x6F6FDEB1,0xC5C59154, + 0x30306050,0x01010203,0x6767CEA9,0x2B2B567D,0xFEFEE719,0xD7D7B562,0xABAB4DE6,0x7676EC9A, + 0xCACA8F45,0x82821F9D,0xC9C98940,0x7D7DFA87,0xFAFAEF15,0x5959B2EB,0x47478EC9,0xF0F0FB0B, + 0xADAD41EC,0xD4D4B367,0xA2A25FFD,0xAFAF45EA,0x9C9C23BF,0xA4A453F7,0x7272E496,0xC0C09B5B, + 0xB7B775C2,0xFDFDE11C,0x93933DAE,0x26264C6A,0x36366C5A,0x3F3F7E41,0xF7F7F502,0xCCCC834F, + 0x3434685C,0xA5A551F4,0xE5E5D134,0xF1F1F908,0x7171E293,0xD8D8AB73,0x31316253,0x15152A3F, + 0x0404080C,0xC7C79552,0x23234665,0xC3C39D5E,0x18183028,0x969637A1,0x05050A0F,0x9A9A2FB5, + 0x07070E09,0x12122436,0x80801B9B,0xE2E2DF3D,0xEBEBCD26,0x27274E69,0xB2B27FCD,0x7575EA9F, + 0x0909121B,0x83831D9E,0x2C2C5874,0x1A1A342E,0x1B1B362D,0x6E6EDCB2,0x5A5AB4EE,0xA0A05BFB, + 0x5252A4F6,0x3B3B764D,0xD6D6B761,0xB3B37DCE,0x2929527B,0xE3E3DD3E,0x2F2F5E71,0x84841397, + 0x5353A6F5,0xD1D1B968,0000000000,0xEDEDC12C,0x20204060,0xFCFCE31F,0xB1B179C8,0x5B5BB6ED, + 0x6A6AD4BE,0xCBCB8D46,0xBEBE67D9,0x3939724B,0x4A4A94DE,0x4C4C98D4,0x5858B0E8,0xCFCF854A, + 0xD0D0BB6B,0xEFEFC52A,0xAAAA4FE5,0xFBFBED16,0x434386C5,0x4D4D9AD7,0x33336655,0x85851194, + 0x45458ACF,0xF9F9E910,0x02020406,0x7F7FFE81,0x5050A0F0,0x3C3C7844,0x9F9F25BA,0xA8A84BE3, + 0x5151A2F3,0xA3A35DFE,0x404080C0,0x8F8F058A,0x92923FAD,0x9D9D21BC,0x38387048,0xF5F5F104, + 0xBCBC63DF,0xB6B677C1,0xDADAAF75,0x21214263,0x10102030,0xFFFFE51A,0xF3F3FD0E,0xD2D2BF6D, + 0xCDCD814C,0x0C0C1814,0x13132635,0xECECC32F,0x5F5FBEE1,0x979735A2,0x444488CC,0x17172E39, + 0xC4C49357,0xA7A755F2,0x7E7EFC82,0x3D3D7A47,0x6464C8AC,0x5D5DBAE7,0x1919322B,0x7373E695, + 0x6060C0A0,0x81811998,0x4F4F9ED1,0xDCDCA37F,0x22224466,0x2A2A547E,0x90903BAB,0x88880B83, + 0x46468CCA,0xEEEEC729,0xB8B86BD3,0x1414283C,0xDEDEA779,0x5E5EBCE2,0x0B0B161D,0xDBDBAD76, + 0xE0E0DB3B,0x32326456,0x3A3A744E,0x0A0A141E,0x494992DB,0x06060C0A,0x2424486C,0x5C5CB8E4, + 0xC2C29F5D,0xD3D3BD6E,0xACAC43EF,0x6262C4A6,0x919139A8,0x959531A4,0xE4E4D337,0x7979F28B, + 0xE7E7D532,0xC8C88B43,0x37376E59,0x6D6DDAB7,0x8D8D018C,0xD5D5B164,0x4E4E9CD2,0xA9A949E0, + 0x6C6CD8B4,0x5656ACFA,0xF4F4F307,0xEAEACF25,0x6565CAAF,0x7A7AF48E,0xAEAE47E9,0x08081018, + 0xBABA6FD5,0x7878F088,0x25254A6F,0x2E2E5C72,0x1C1C3824,0xA6A657F1,0xB4B473C7,0xC6C69751, + 0xE8E8CB23,0xDDDDA17C,0x7474E89C,0x1F1F3E21,0x4B4B96DD,0xBDBD61DC,0x8B8B0D86,0x8A8A0F85, + 0x7070E090,0x3E3E7C42,0xB5B571C4,0x6666CCAA,0x484890D8,0x03030605,0xF6F6F701,0x0E0E1C12, + 0x6161C2A3,0x35356A5F,0x5757AEF9,0xB9B969D0,0x86861791,0xC1C19958,0x1D1D3A27,0x9E9E27B9, + 0xE1E1D938,0xF8F8EB13,0x98982BB3,0x11112233,0x6969D2BB,0xD9D9A970,0x8E8E0789,0x949433A7, + 0x9B9B2DB6,0x1E1E3C22,0x87871592,0xE9E9C920,0xCECE8749,0x5555AAFF,0x28285078,0xDFDFA57A, + 0x8C8C038F,0xA1A159F8,0x89890980,0x0D0D1A17,0xBFBF65DA,0xE6E6D731,0x424284C6,0x6868D0B8, + 0x414182C3,0x999929B0,0x2D2D5A77,0x0F0F1E11,0xB0B07BCB,0x5454A8FC,0xBBBB6DD6,0x16162C3A + }, + { + 0x63C6A563,0x7CF8847C,0x77EE9977,0x7BF68D7B,0xF2FF0DF2,0x6BD6BD6B,0x6FDEB16F,0xC59154C5, + 0x30605030,0x01020301,0x67CEA967,0x2B567D2B,0xFEE719FE,0xD7B562D7,0xAB4DE6AB,0x76EC9A76, + 0xCA8F45CA,0x821F9D82,0xC98940C9,0x7DFA877D,0xFAEF15FA,0x59B2EB59,0x478EC947,0xF0FB0BF0, + 0xAD41ECAD,0xD4B367D4,0xA25FFDA2,0xAF45EAAF,0x9C23BF9C,0xA453F7A4,0x72E49672,0xC09B5BC0, + 0xB775C2B7,0xFDE11CFD,0x933DAE93,0x264C6A26,0x366C5A36,0x3F7E413F,0xF7F502F7,0xCC834FCC, + 0x34685C34,0xA551F4A5,0xE5D134E5,0xF1F908F1,0x71E29371,0xD8AB73D8,0x31625331,0x152A3F15, + 0x04080C04,0xC79552C7,0x23466523,0xC39D5EC3,0x18302818,0x9637A196,0x050A0F05,0x9A2FB59A, + 0x070E0907,0x12243612,0x801B9B80,0xE2DF3DE2,0xEBCD26EB,0x274E6927,0xB27FCDB2,0x75EA9F75, + 0x09121B09,0x831D9E83,0x2C58742C,0x1A342E1A,0x1B362D1B,0x6EDCB26E,0x5AB4EE5A,0xA05BFBA0, + 0x52A4F652,0x3B764D3B,0xD6B761D6,0xB37DCEB3,0x29527B29,0xE3DD3EE3,0x2F5E712F,0x84139784, + 0x53A6F553,0xD1B968D1,0000000000,0xEDC12CED,0x20406020,0xFCE31FFC,0xB179C8B1,0x5BB6ED5B, + 0x6AD4BE6A,0xCB8D46CB,0xBE67D9BE,0x39724B39,0x4A94DE4A,0x4C98D44C,0x58B0E858,0xCF854ACF, + 0xD0BB6BD0,0xEFC52AEF,0xAA4FE5AA,0xFBED16FB,0x4386C543,0x4D9AD74D,0x33665533,0x85119485, + 0x458ACF45,0xF9E910F9,0x02040602,0x7FFE817F,0x50A0F050,0x3C78443C,0x9F25BA9F,0xA84BE3A8, + 0x51A2F351,0xA35DFEA3,0x4080C040,0x8F058A8F,0x923FAD92,0x9D21BC9D,0x38704838,0xF5F104F5, + 0xBC63DFBC,0xB677C1B6,0xDAAF75DA,0x21426321,0x10203010,0xFFE51AFF,0xF3FD0EF3,0xD2BF6DD2, + 0xCD814CCD,0x0C18140C,0x13263513,0xECC32FEC,0x5FBEE15F,0x9735A297,0x4488CC44,0x172E3917, + 0xC49357C4,0xA755F2A7,0x7EFC827E,0x3D7A473D,0x64C8AC64,0x5DBAE75D,0x19322B19,0x73E69573, + 0x60C0A060,0x81199881,0x4F9ED14F,0xDCA37FDC,0x22446622,0x2A547E2A,0x903BAB90,0x880B8388, + 0x468CCA46,0xEEC729EE,0xB86BD3B8,0x14283C14,0xDEA779DE,0x5EBCE25E,0x0B161D0B,0xDBAD76DB, + 0xE0DB3BE0,0x32645632,0x3A744E3A,0x0A141E0A,0x4992DB49,0x060C0A06,0x24486C24,0x5CB8E45C, + 0xC29F5DC2,0xD3BD6ED3,0xAC43EFAC,0x62C4A662,0x9139A891,0x9531A495,0xE4D337E4,0x79F28B79, + 0xE7D532E7,0xC88B43C8,0x376E5937,0x6DDAB76D,0x8D018C8D,0xD5B164D5,0x4E9CD24E,0xA949E0A9, + 0x6CD8B46C,0x56ACFA56,0xF4F307F4,0xEACF25EA,0x65CAAF65,0x7AF48E7A,0xAE47E9AE,0x08101808, + 0xBA6FD5BA,0x78F08878,0x254A6F25,0x2E5C722E,0x1C38241C,0xA657F1A6,0xB473C7B4,0xC69751C6, + 0xE8CB23E8,0xDDA17CDD,0x74E89C74,0x1F3E211F,0x4B96DD4B,0xBD61DCBD,0x8B0D868B,0x8A0F858A, + 0x70E09070,0x3E7C423E,0xB571C4B5,0x66CCAA66,0x4890D848,0x03060503,0xF6F701F6,0x0E1C120E, + 0x61C2A361,0x356A5F35,0x57AEF957,0xB969D0B9,0x86179186,0xC19958C1,0x1D3A271D,0x9E27B99E, + 0xE1D938E1,0xF8EB13F8,0x982BB398,0x11223311,0x69D2BB69,0xD9A970D9,0x8E07898E,0x9433A794, + 0x9B2DB69B,0x1E3C221E,0x87159287,0xE9C920E9,0xCE8749CE,0x55AAFF55,0x28507828,0xDFA57ADF, + 0x8C038F8C,0xA159F8A1,0x89098089,0x0D1A170D,0xBF65DABF,0xE6D731E6,0x4284C642,0x68D0B868, + 0x4182C341,0x9929B099,0x2D5A772D,0x0F1E110F,0xB07BCBB0,0x54A8FC54,0xBB6DD6BB,0x162C3A16 + }, + { + 0xC6A56363,0xF8847C7C,0xEE997777,0xF68D7B7B,0xFF0DF2F2,0xD6BD6B6B,0xDEB16F6F,0x9154C5C5, + 0x60503030,0x02030101,0xCEA96767,0x567D2B2B,0xE719FEFE,0xB562D7D7,0x4DE6ABAB,0xEC9A7676, + 0x8F45CACA,0x1F9D8282,0x8940C9C9,0xFA877D7D,0xEF15FAFA,0xB2EB5959,0x8EC94747,0xFB0BF0F0, + 0x41ECADAD,0xB367D4D4,0x5FFDA2A2,0x45EAAFAF,0x23BF9C9C,0x53F7A4A4,0xE4967272,0x9B5BC0C0, + 0x75C2B7B7,0xE11CFDFD,0x3DAE9393,0x4C6A2626,0x6C5A3636,0x7E413F3F,0xF502F7F7,0x834FCCCC, + 0x685C3434,0x51F4A5A5,0xD134E5E5,0xF908F1F1,0xE2937171,0xAB73D8D8,0x62533131,0x2A3F1515, + 0x080C0404,0x9552C7C7,0x46652323,0x9D5EC3C3,0x30281818,0x37A19696,0x0A0F0505,0x2FB59A9A, + 0x0E090707,0x24361212,0x1B9B8080,0xDF3DE2E2,0xCD26EBEB,0x4E692727,0x7FCDB2B2,0xEA9F7575, + 0x121B0909,0x1D9E8383,0x58742C2C,0x342E1A1A,0x362D1B1B,0xDCB26E6E,0xB4EE5A5A,0x5BFBA0A0, + 0xA4F65252,0x764D3B3B,0xB761D6D6,0x7DCEB3B3,0x527B2929,0xDD3EE3E3,0x5E712F2F,0x13978484, + 0xA6F55353,0xB968D1D1,0000000000,0xC12CEDED,0x40602020,0xE31FFCFC,0x79C8B1B1,0xB6ED5B5B, + 0xD4BE6A6A,0x8D46CBCB,0x67D9BEBE,0x724B3939,0x94DE4A4A,0x98D44C4C,0xB0E85858,0x854ACFCF, + 0xBB6BD0D0,0xC52AEFEF,0x4FE5AAAA,0xED16FBFB,0x86C54343,0x9AD74D4D,0x66553333,0x11948585, + 0x8ACF4545,0xE910F9F9,0x04060202,0xFE817F7F,0xA0F05050,0x78443C3C,0x25BA9F9F,0x4BE3A8A8, + 0xA2F35151,0x5DFEA3A3,0x80C04040,0x058A8F8F,0x3FAD9292,0x21BC9D9D,0x70483838,0xF104F5F5, + 0x63DFBCBC,0x77C1B6B6,0xAF75DADA,0x42632121,0x20301010,0xE51AFFFF,0xFD0EF3F3,0xBF6DD2D2, + 0x814CCDCD,0x18140C0C,0x26351313,0xC32FECEC,0xBEE15F5F,0x35A29797,0x88CC4444,0x2E391717, + 0x9357C4C4,0x55F2A7A7,0xFC827E7E,0x7A473D3D,0xC8AC6464,0xBAE75D5D,0x322B1919,0xE6957373, + 0xC0A06060,0x19988181,0x9ED14F4F,0xA37FDCDC,0x44662222,0x547E2A2A,0x3BAB9090,0x0B838888, + 0x8CCA4646,0xC729EEEE,0x6BD3B8B8,0x283C1414,0xA779DEDE,0xBCE25E5E,0x161D0B0B,0xAD76DBDB, + 0xDB3BE0E0,0x64563232,0x744E3A3A,0x141E0A0A,0x92DB4949,0x0C0A0606,0x486C2424,0xB8E45C5C, + 0x9F5DC2C2,0xBD6ED3D3,0x43EFACAC,0xC4A66262,0x39A89191,0x31A49595,0xD337E4E4,0xF28B7979, + 0xD532E7E7,0x8B43C8C8,0x6E593737,0xDAB76D6D,0x018C8D8D,0xB164D5D5,0x9CD24E4E,0x49E0A9A9, + 0xD8B46C6C,0xACFA5656,0xF307F4F4,0xCF25EAEA,0xCAAF6565,0xF48E7A7A,0x47E9AEAE,0x10180808, + 0x6FD5BABA,0xF0887878,0x4A6F2525,0x5C722E2E,0x38241C1C,0x57F1A6A6,0x73C7B4B4,0x9751C6C6, + 0xCB23E8E8,0xA17CDDDD,0xE89C7474,0x3E211F1F,0x96DD4B4B,0x61DCBDBD,0x0D868B8B,0x0F858A8A, + 0xE0907070,0x7C423E3E,0x71C4B5B5,0xCCAA6666,0x90D84848,0x06050303,0xF701F6F6,0x1C120E0E, + 0xC2A36161,0x6A5F3535,0xAEF95757,0x69D0B9B9,0x17918686,0x9958C1C1,0x3A271D1D,0x27B99E9E, + 0xD938E1E1,0xEB13F8F8,0x2BB39898,0x22331111,0xD2BB6969,0xA970D9D9,0x07898E8E,0x33A79494, + 0x2DB69B9B,0x3C221E1E,0x15928787,0xC920E9E9,0x8749CECE,0xAAFF5555,0x50782828,0xA57ADFDF, + 0x038F8C8C,0x59F8A1A1,0x09808989,0x1A170D0D,0x65DABFBF,0xD731E6E6,0x84C64242,0xD0B86868, + 0x82C34141,0x29B09999,0x5A772D2D,0x1E110F0F,0x7BCBB0B0,0xA8FC5454,0x6DD6BBBB,0x2C3A1616 + } }; -static uint32_t fl_tab[4][256] = -{ - { - 0x00000063,0x0000007C,0x00000077,0x0000007B,0x000000F2,0x0000006B,0x0000006F,0x000000C5, - 0x00000030,0x00000001,0x00000067,0x0000002B,0x000000FE,0x000000D7,0x000000AB,0x00000076, - 0x000000CA,0x00000082,0x000000C9,0x0000007D,0x000000FA,0x00000059,0x00000047,0x000000F0, - 0x000000AD,0x000000D4,0x000000A2,0x000000AF,0x0000009C,0x000000A4,0x00000072,0x000000C0, - 0x000000B7,0x000000FD,0x00000093,0x00000026,0x00000036,0x0000003F,0x000000F7,0x000000CC, - 0x00000034,0x000000A5,0x000000E5,0x000000F1,0x00000071,0x000000D8,0x00000031,0x00000015, - 0x00000004,0x000000C7,0x00000023,0x000000C3,0x00000018,0x00000096,0x00000005,0x0000009A, - 0x00000007,0x00000012,0x00000080,0x000000E2,0x000000EB,0x00000027,0x000000B2,0x00000075, - 0x00000009,0x00000083,0x0000002C,0x0000001A,0x0000001B,0x0000006E,0x0000005A,0x000000A0, - 0x00000052,0x0000003B,0x000000D6,0x000000B3,0x00000029,0x000000E3,0x0000002F,0x00000084, - 0x00000053,0x000000D1,0x00000000,0x000000ED,0x00000020,0x000000FC,0x000000B1,0x0000005B, - 0x0000006A,0x000000CB,0x000000BE,0x00000039,0x0000004A,0x0000004C,0x00000058,0x000000CF, - 0x000000D0,0x000000EF,0x000000AA,0x000000FB,0x00000043,0x0000004D,0x00000033,0x00000085, - 0x00000045,0x000000F9,0x00000002,0x0000007F,0x00000050,0x0000003C,0x0000009F,0x000000A8, - 0x00000051,0x000000A3,0x00000040,0x0000008F,0x00000092,0x0000009D,0x00000038,0x000000F5, - 0x000000BC,0x000000B6,0x000000DA,0x00000021,0x00000010,0x000000FF,0x000000F3,0x000000D2, - 0x000000CD,0x0000000C,0x00000013,0x000000EC,0x0000005F,0x00000097,0x00000044,0x00000017, - 0x000000C4,0x000000A7,0x0000007E,0x0000003D,0x00000064,0x0000005D,0x00000019,0x00000073, - 0x00000060,0x00000081,0x0000004F,0x000000DC,0x00000022,0x0000002A,0x00000090,0x00000088, - 0x00000046,0x000000EE,0x000000B8,0x00000014,0x000000DE,0x0000005E,0x0000000B,0x000000DB, - 0x000000E0,0x00000032,0x0000003A,0x0000000A,0x00000049,0x00000006,0x00000024,0x0000005C, - 0x000000C2,0x000000D3,0x000000AC,0x00000062,0x00000091,0x00000095,0x000000E4,0x00000079, - 0x000000E7,0x000000C8,0x00000037,0x0000006D,0x0000008D,0x000000D5,0x0000004E,0x000000A9, - 0x0000006C,0x00000056,0x000000F4,0x000000EA,0x00000065,0x0000007A,0x000000AE,0x00000008, - 0x000000BA,0x00000078,0x00000025,0x0000002E,0x0000001C,0x000000A6,0x000000B4,0x000000C6, - 0x000000E8,0x000000DD,0x00000074,0x0000001F,0x0000004B,0x000000BD,0x0000008B,0x0000008A, - 0x00000070,0x0000003E,0x000000B5,0x00000066,0x00000048,0x00000003,0x000000F6,0x0000000E, - 0x00000061,0x00000035,0x00000057,0x000000B9,0x00000086,0x000000C1,0x0000001D,0x0000009E, - 0x000000E1,0x000000F8,0x00000098,0x00000011,0x00000069,0x000000D9,0x0000008E,0x00000094, - 0x0000009B,0x0000001E,0x00000087,0x000000E9,0x000000CE,0x00000055,0x00000028,0x000000DF, - 0x0000008C,0x000000A1,0x00000089,0x0000000D,0x000000BF,0x000000E6,0x00000042,0x00000068, - 0x00000041,0x00000099,0x0000002D,0x0000000F,0x000000B0,0x00000054,0x000000BB,0x00000016 - }, - { - 0x00006300,0x00007C00,0x00007700,0x00007B00,0x0000F200,0x00006B00,0x00006F00,0x0000C500, - 0x00003000,0x00000100,0x00006700,0x00002B00,0x0000FE00,0x0000D700,0x0000AB00,0x00007600, - 0x0000CA00,0x00008200,0x0000C900,0x00007D00,0x0000FA00,0x00005900,0x00004700,0x0000F000, - 0x0000AD00,0x0000D400,0x0000A200,0x0000AF00,0x00009C00,0x0000A400,0x00007200,0x0000C000, - 0x0000B700,0x0000FD00,0x00009300,0x00002600,0x00003600,0x00003F00,0x0000F700,0x0000CC00, - 0x00003400,0x0000A500,0x0000E500,0x0000F100,0x00007100,0x0000D800,0x00003100,0x00001500, - 0x00000400,0x0000C700,0x00002300,0x0000C300,0x00001800,0x00009600,0x00000500,0x00009A00, - 0x00000700,0x00001200,0x00008000,0x0000E200,0x0000EB00,0x00002700,0x0000B200,0x00007500, - 0x00000900,0x00008300,0x00002C00,0x00001A00,0x00001B00,0x00006E00,0x00005A00,0x0000A000, - 0x00005200,0x00003B00,0x0000D600,0x0000B300,0x00002900,0x0000E300,0x00002F00,0x00008400, - 0x00005300,0x0000D100,0000000000,0x0000ED00,0x00002000,0x0000FC00,0x0000B100,0x00005B00, - 0x00006A00,0x0000CB00,0x0000BE00,0x00003900,0x00004A00,0x00004C00,0x00005800,0x0000CF00, - 0x0000D000,0x0000EF00,0x0000AA00,0x0000FB00,0x00004300,0x00004D00,0x00003300,0x00008500, - 0x00004500,0x0000F900,0x00000200,0x00007F00,0x00005000,0x00003C00,0x00009F00,0x0000A800, - 0x00005100,0x0000A300,0x00004000,0x00008F00,0x00009200,0x00009D00,0x00003800,0x0000F500, - 0x0000BC00,0x0000B600,0x0000DA00,0x00002100,0x00001000,0x0000FF00,0x0000F300,0x0000D200, - 0x0000CD00,0x00000C00,0x00001300,0x0000EC00,0x00005F00,0x00009700,0x00004400,0x00001700, - 0x0000C400,0x0000A700,0x00007E00,0x00003D00,0x00006400,0x00005D00,0x00001900,0x00007300, - 0x00006000,0x00008100,0x00004F00,0x0000DC00,0x00002200,0x00002A00,0x00009000,0x00008800, - 0x00004600,0x0000EE00,0x0000B800,0x00001400,0x0000DE00,0x00005E00,0x00000B00,0x0000DB00, - 0x0000E000,0x00003200,0x00003A00,0x00000A00,0x00004900,0x00000600,0x00002400,0x00005C00, - 0x0000C200,0x0000D300,0x0000AC00,0x00006200,0x00009100,0x00009500,0x0000E400,0x00007900, - 0x0000E700,0x0000C800,0x00003700,0x00006D00,0x00008D00,0x0000D500,0x00004E00,0x0000A900, - 0x00006C00,0x00005600,0x0000F400,0x0000EA00,0x00006500,0x00007A00,0x0000AE00,0x00000800, - 0x0000BA00,0x00007800,0x00002500,0x00002E00,0x00001C00,0x0000A600,0x0000B400,0x0000C600, - 0x0000E800,0x0000DD00,0x00007400,0x00001F00,0x00004B00,0x0000BD00,0x00008B00,0x00008A00, - 0x00007000,0x00003E00,0x0000B500,0x00006600,0x00004800,0x00000300,0x0000F600,0x00000E00, - 0x00006100,0x00003500,0x00005700,0x0000B900,0x00008600,0x0000C100,0x00001D00,0x00009E00, - 0x0000E100,0x0000F800,0x00009800,0x00001100,0x00006900,0x0000D900,0x00008E00,0x00009400, - 0x00009B00,0x00001E00,0x00008700,0x0000E900,0x0000CE00,0x00005500,0x00002800,0x0000DF00, - 0x00008C00,0x0000A100,0x00008900,0x00000D00,0x0000BF00,0x0000E600,0x00004200,0x00006800, - 0x00004100,0x00009900,0x00002D00,0x00000F00,0x0000B000,0x00005400,0x0000BB00,0x00001600 - }, - { - 0x00630000,0x007C0000,0x00770000,0x007B0000,0x00F20000,0x006B0000,0x006F0000,0x00C50000, - 0x00300000,0x00010000,0x00670000,0x002B0000,0x00FE0000,0x00D70000,0x00AB0000,0x00760000, - 0x00CA0000,0x00820000,0x00C90000,0x007D0000,0x00FA0000,0x00590000,0x00470000,0x00F00000, - 0x00AD0000,0x00D40000,0x00A20000,0x00AF0000,0x009C0000,0x00A40000,0x00720000,0x00C00000, - 0x00B70000,0x00FD0000,0x00930000,0x00260000,0x00360000,0x003F0000,0x00F70000,0x00CC0000, - 0x00340000,0x00A50000,0x00E50000,0x00F10000,0x00710000,0x00D80000,0x00310000,0x00150000, - 0x00040000,0x00C70000,0x00230000,0x00C30000,0x00180000,0x00960000,0x00050000,0x009A0000, - 0x00070000,0x00120000,0x00800000,0x00E20000,0x00EB0000,0x00270000,0x00B20000,0x00750000, - 0x00090000,0x00830000,0x002C0000,0x001A0000,0x001B0000,0x006E0000,0x005A0000,0x00A00000, - 0x00520000,0x003B0000,0x00D60000,0x00B30000,0x00290000,0x00E30000,0x002F0000,0x00840000, - 0x00530000,0x00D10000,0000000000,0x00ED0000,0x00200000,0x00FC0000,0x00B10000,0x005B0000, - 0x006A0000,0x00CB0000,0x00BE0000,0x00390000,0x004A0000,0x004C0000,0x00580000,0x00CF0000, - 0x00D00000,0x00EF0000,0x00AA0000,0x00FB0000,0x00430000,0x004D0000,0x00330000,0x00850000, - 0x00450000,0x00F90000,0x00020000,0x007F0000,0x00500000,0x003C0000,0x009F0000,0x00A80000, - 0x00510000,0x00A30000,0x00400000,0x008F0000,0x00920000,0x009D0000,0x00380000,0x00F50000, - 0x00BC0000,0x00B60000,0x00DA0000,0x00210000,0x00100000,0x00FF0000,0x00F30000,0x00D20000, - 0x00CD0000,0x000C0000,0x00130000,0x00EC0000,0x005F0000,0x00970000,0x00440000,0x00170000, - 0x00C40000,0x00A70000,0x007E0000,0x003D0000,0x00640000,0x005D0000,0x00190000,0x00730000, - 0x00600000,0x00810000,0x004F0000,0x00DC0000,0x00220000,0x002A0000,0x00900000,0x00880000, - 0x00460000,0x00EE0000,0x00B80000,0x00140000,0x00DE0000,0x005E0000,0x000B0000,0x00DB0000, - 0x00E00000,0x00320000,0x003A0000,0x000A0000,0x00490000,0x00060000,0x00240000,0x005C0000, - 0x00C20000,0x00D30000,0x00AC0000,0x00620000,0x00910000,0x00950000,0x00E40000,0x00790000, - 0x00E70000,0x00C80000,0x00370000,0x006D0000,0x008D0000,0x00D50000,0x004E0000,0x00A90000, - 0x006C0000,0x00560000,0x00F40000,0x00EA0000,0x00650000,0x007A0000,0x00AE0000,0x00080000, - 0x00BA0000,0x00780000,0x00250000,0x002E0000,0x001C0000,0x00A60000,0x00B40000,0x00C60000, - 0x00E80000,0x00DD0000,0x00740000,0x001F0000,0x004B0000,0x00BD0000,0x008B0000,0x008A0000, - 0x00700000,0x003E0000,0x00B50000,0x00660000,0x00480000,0x00030000,0x00F60000,0x000E0000, - 0x00610000,0x00350000,0x00570000,0x00B90000,0x00860000,0x00C10000,0x001D0000,0x009E0000, - 0x00E10000,0x00F80000,0x00980000,0x00110000,0x00690000,0x00D90000,0x008E0000,0x00940000, - 0x009B0000,0x001E0000,0x00870000,0x00E90000,0x00CE0000,0x00550000,0x00280000,0x00DF0000, - 0x008C0000,0x00A10000,0x00890000,0x000D0000,0x00BF0000,0x00E60000,0x00420000,0x00680000, - 0x00410000,0x00990000,0x002D0000,0x000F0000,0x00B00000,0x00540000,0x00BB0000,0x00160000 - }, - { - 0x63000000,0x7C000000,0x77000000,0x7B000000,0xF2000000,0x6B000000,0x6F000000,0xC5000000, - 0x30000000,0x01000000,0x67000000,0x2B000000,0xFE000000,0xD7000000,0xAB000000,0x76000000, - 0xCA000000,0x82000000,0xC9000000,0x7D000000,0xFA000000,0x59000000,0x47000000,0xF0000000, - 0xAD000000,0xD4000000,0xA2000000,0xAF000000,0x9C000000,0xA4000000,0x72000000,0xC0000000, - 0xB7000000,0xFD000000,0x93000000,0x26000000,0x36000000,0x3F000000,0xF7000000,0xCC000000, - 0x34000000,0xA5000000,0xE5000000,0xF1000000,0x71000000,0xD8000000,0x31000000,0x15000000, - 0x04000000,0xC7000000,0x23000000,0xC3000000,0x18000000,0x96000000,0x05000000,0x9A000000, - 0x07000000,0x12000000,0x80000000,0xE2000000,0xEB000000,0x27000000,0xB2000000,0x75000000, - 0x09000000,0x83000000,0x2C000000,0x1A000000,0x1B000000,0x6E000000,0x5A000000,0xA0000000, - 0x52000000,0x3B000000,0xD6000000,0xB3000000,0x29000000,0xE3000000,0x2F000000,0x84000000, - 0x53000000,0xD1000000,0000000000,0xED000000,0x20000000,0xFC000000,0xB1000000,0x5B000000, - 0x6A000000,0xCB000000,0xBE000000,0x39000000,0x4A000000,0x4C000000,0x58000000,0xCF000000, - 0xD0000000,0xEF000000,0xAA000000,0xFB000000,0x43000000,0x4D000000,0x33000000,0x85000000, - 0x45000000,0xF9000000,0x02000000,0x7F000000,0x50000000,0x3C000000,0x9F000000,0xA8000000, - 0x51000000,0xA3000000,0x40000000,0x8F000000,0x92000000,0x9D000000,0x38000000,0xF5000000, - 0xBC000000,0xB6000000,0xDA000000,0x21000000,0x10000000,0xFF000000,0xF3000000,0xD2000000, - 0xCD000000,0x0C000000,0x13000000,0xEC000000,0x5F000000,0x97000000,0x44000000,0x17000000, - 0xC4000000,0xA7000000,0x7E000000,0x3D000000,0x64000000,0x5D000000,0x19000000,0x73000000, - 0x60000000,0x81000000,0x4F000000,0xDC000000,0x22000000,0x2A000000,0x90000000,0x88000000, - 0x46000000,0xEE000000,0xB8000000,0x14000000,0xDE000000,0x5E000000,0x0B000000,0xDB000000, - 0xE0000000,0x32000000,0x3A000000,0x0A000000,0x49000000,0x06000000,0x24000000,0x5C000000, - 0xC2000000,0xD3000000,0xAC000000,0x62000000,0x91000000,0x95000000,0xE4000000,0x79000000, - 0xE7000000,0xC8000000,0x37000000,0x6D000000,0x8D000000,0xD5000000,0x4E000000,0xA9000000, - 0x6C000000,0x56000000,0xF4000000,0xEA000000,0x65000000,0x7A000000,0xAE000000,0x08000000, - 0xBA000000,0x78000000,0x25000000,0x2E000000,0x1C000000,0xA6000000,0xB4000000,0xC6000000, - 0xE8000000,0xDD000000,0x74000000,0x1F000000,0x4B000000,0xBD000000,0x8B000000,0x8A000000, - 0x70000000,0x3E000000,0xB5000000,0x66000000,0x48000000,0x03000000,0xF6000000,0x0E000000, - 0x61000000,0x35000000,0x57000000,0xB9000000,0x86000000,0xC1000000,0x1D000000,0x9E000000, - 0xE1000000,0xF8000000,0x98000000,0x11000000,0x69000000,0xD9000000,0x8E000000,0x94000000, - 0x9B000000,0x1E000000,0x87000000,0xE9000000,0xCE000000,0x55000000,0x28000000,0xDF000000, - 0x8C000000,0xA1000000,0x89000000,0x0D000000,0xBF000000,0xE6000000,0x42000000,0x68000000, - 0x41000000,0x99000000,0x2D000000,0x0F000000,0xB0000000,0x54000000,0xBB000000,0x16000000 - } +static uint32_t fl_tab[4][256] = { + { + 0x00000063,0x0000007C,0x00000077,0x0000007B,0x000000F2,0x0000006B,0x0000006F,0x000000C5, + 0x00000030,0x00000001,0x00000067,0x0000002B,0x000000FE,0x000000D7,0x000000AB,0x00000076, + 0x000000CA,0x00000082,0x000000C9,0x0000007D,0x000000FA,0x00000059,0x00000047,0x000000F0, + 0x000000AD,0x000000D4,0x000000A2,0x000000AF,0x0000009C,0x000000A4,0x00000072,0x000000C0, + 0x000000B7,0x000000FD,0x00000093,0x00000026,0x00000036,0x0000003F,0x000000F7,0x000000CC, + 0x00000034,0x000000A5,0x000000E5,0x000000F1,0x00000071,0x000000D8,0x00000031,0x00000015, + 0x00000004,0x000000C7,0x00000023,0x000000C3,0x00000018,0x00000096,0x00000005,0x0000009A, + 0x00000007,0x00000012,0x00000080,0x000000E2,0x000000EB,0x00000027,0x000000B2,0x00000075, + 0x00000009,0x00000083,0x0000002C,0x0000001A,0x0000001B,0x0000006E,0x0000005A,0x000000A0, + 0x00000052,0x0000003B,0x000000D6,0x000000B3,0x00000029,0x000000E3,0x0000002F,0x00000084, + 0x00000053,0x000000D1,0x00000000,0x000000ED,0x00000020,0x000000FC,0x000000B1,0x0000005B, + 0x0000006A,0x000000CB,0x000000BE,0x00000039,0x0000004A,0x0000004C,0x00000058,0x000000CF, + 0x000000D0,0x000000EF,0x000000AA,0x000000FB,0x00000043,0x0000004D,0x00000033,0x00000085, + 0x00000045,0x000000F9,0x00000002,0x0000007F,0x00000050,0x0000003C,0x0000009F,0x000000A8, + 0x00000051,0x000000A3,0x00000040,0x0000008F,0x00000092,0x0000009D,0x00000038,0x000000F5, + 0x000000BC,0x000000B6,0x000000DA,0x00000021,0x00000010,0x000000FF,0x000000F3,0x000000D2, + 0x000000CD,0x0000000C,0x00000013,0x000000EC,0x0000005F,0x00000097,0x00000044,0x00000017, + 0x000000C4,0x000000A7,0x0000007E,0x0000003D,0x00000064,0x0000005D,0x00000019,0x00000073, + 0x00000060,0x00000081,0x0000004F,0x000000DC,0x00000022,0x0000002A,0x00000090,0x00000088, + 0x00000046,0x000000EE,0x000000B8,0x00000014,0x000000DE,0x0000005E,0x0000000B,0x000000DB, + 0x000000E0,0x00000032,0x0000003A,0x0000000A,0x00000049,0x00000006,0x00000024,0x0000005C, + 0x000000C2,0x000000D3,0x000000AC,0x00000062,0x00000091,0x00000095,0x000000E4,0x00000079, + 0x000000E7,0x000000C8,0x00000037,0x0000006D,0x0000008D,0x000000D5,0x0000004E,0x000000A9, + 0x0000006C,0x00000056,0x000000F4,0x000000EA,0x00000065,0x0000007A,0x000000AE,0x00000008, + 0x000000BA,0x00000078,0x00000025,0x0000002E,0x0000001C,0x000000A6,0x000000B4,0x000000C6, + 0x000000E8,0x000000DD,0x00000074,0x0000001F,0x0000004B,0x000000BD,0x0000008B,0x0000008A, + 0x00000070,0x0000003E,0x000000B5,0x00000066,0x00000048,0x00000003,0x000000F6,0x0000000E, + 0x00000061,0x00000035,0x00000057,0x000000B9,0x00000086,0x000000C1,0x0000001D,0x0000009E, + 0x000000E1,0x000000F8,0x00000098,0x00000011,0x00000069,0x000000D9,0x0000008E,0x00000094, + 0x0000009B,0x0000001E,0x00000087,0x000000E9,0x000000CE,0x00000055,0x00000028,0x000000DF, + 0x0000008C,0x000000A1,0x00000089,0x0000000D,0x000000BF,0x000000E6,0x00000042,0x00000068, + 0x00000041,0x00000099,0x0000002D,0x0000000F,0x000000B0,0x00000054,0x000000BB,0x00000016 + }, + { + 0x00006300,0x00007C00,0x00007700,0x00007B00,0x0000F200,0x00006B00,0x00006F00,0x0000C500, + 0x00003000,0x00000100,0x00006700,0x00002B00,0x0000FE00,0x0000D700,0x0000AB00,0x00007600, + 0x0000CA00,0x00008200,0x0000C900,0x00007D00,0x0000FA00,0x00005900,0x00004700,0x0000F000, + 0x0000AD00,0x0000D400,0x0000A200,0x0000AF00,0x00009C00,0x0000A400,0x00007200,0x0000C000, + 0x0000B700,0x0000FD00,0x00009300,0x00002600,0x00003600,0x00003F00,0x0000F700,0x0000CC00, + 0x00003400,0x0000A500,0x0000E500,0x0000F100,0x00007100,0x0000D800,0x00003100,0x00001500, + 0x00000400,0x0000C700,0x00002300,0x0000C300,0x00001800,0x00009600,0x00000500,0x00009A00, + 0x00000700,0x00001200,0x00008000,0x0000E200,0x0000EB00,0x00002700,0x0000B200,0x00007500, + 0x00000900,0x00008300,0x00002C00,0x00001A00,0x00001B00,0x00006E00,0x00005A00,0x0000A000, + 0x00005200,0x00003B00,0x0000D600,0x0000B300,0x00002900,0x0000E300,0x00002F00,0x00008400, + 0x00005300,0x0000D100,0000000000,0x0000ED00,0x00002000,0x0000FC00,0x0000B100,0x00005B00, + 0x00006A00,0x0000CB00,0x0000BE00,0x00003900,0x00004A00,0x00004C00,0x00005800,0x0000CF00, + 0x0000D000,0x0000EF00,0x0000AA00,0x0000FB00,0x00004300,0x00004D00,0x00003300,0x00008500, + 0x00004500,0x0000F900,0x00000200,0x00007F00,0x00005000,0x00003C00,0x00009F00,0x0000A800, + 0x00005100,0x0000A300,0x00004000,0x00008F00,0x00009200,0x00009D00,0x00003800,0x0000F500, + 0x0000BC00,0x0000B600,0x0000DA00,0x00002100,0x00001000,0x0000FF00,0x0000F300,0x0000D200, + 0x0000CD00,0x00000C00,0x00001300,0x0000EC00,0x00005F00,0x00009700,0x00004400,0x00001700, + 0x0000C400,0x0000A700,0x00007E00,0x00003D00,0x00006400,0x00005D00,0x00001900,0x00007300, + 0x00006000,0x00008100,0x00004F00,0x0000DC00,0x00002200,0x00002A00,0x00009000,0x00008800, + 0x00004600,0x0000EE00,0x0000B800,0x00001400,0x0000DE00,0x00005E00,0x00000B00,0x0000DB00, + 0x0000E000,0x00003200,0x00003A00,0x00000A00,0x00004900,0x00000600,0x00002400,0x00005C00, + 0x0000C200,0x0000D300,0x0000AC00,0x00006200,0x00009100,0x00009500,0x0000E400,0x00007900, + 0x0000E700,0x0000C800,0x00003700,0x00006D00,0x00008D00,0x0000D500,0x00004E00,0x0000A900, + 0x00006C00,0x00005600,0x0000F400,0x0000EA00,0x00006500,0x00007A00,0x0000AE00,0x00000800, + 0x0000BA00,0x00007800,0x00002500,0x00002E00,0x00001C00,0x0000A600,0x0000B400,0x0000C600, + 0x0000E800,0x0000DD00,0x00007400,0x00001F00,0x00004B00,0x0000BD00,0x00008B00,0x00008A00, + 0x00007000,0x00003E00,0x0000B500,0x00006600,0x00004800,0x00000300,0x0000F600,0x00000E00, + 0x00006100,0x00003500,0x00005700,0x0000B900,0x00008600,0x0000C100,0x00001D00,0x00009E00, + 0x0000E100,0x0000F800,0x00009800,0x00001100,0x00006900,0x0000D900,0x00008E00,0x00009400, + 0x00009B00,0x00001E00,0x00008700,0x0000E900,0x0000CE00,0x00005500,0x00002800,0x0000DF00, + 0x00008C00,0x0000A100,0x00008900,0x00000D00,0x0000BF00,0x0000E600,0x00004200,0x00006800, + 0x00004100,0x00009900,0x00002D00,0x00000F00,0x0000B000,0x00005400,0x0000BB00,0x00001600 + }, + { + 0x00630000,0x007C0000,0x00770000,0x007B0000,0x00F20000,0x006B0000,0x006F0000,0x00C50000, + 0x00300000,0x00010000,0x00670000,0x002B0000,0x00FE0000,0x00D70000,0x00AB0000,0x00760000, + 0x00CA0000,0x00820000,0x00C90000,0x007D0000,0x00FA0000,0x00590000,0x00470000,0x00F00000, + 0x00AD0000,0x00D40000,0x00A20000,0x00AF0000,0x009C0000,0x00A40000,0x00720000,0x00C00000, + 0x00B70000,0x00FD0000,0x00930000,0x00260000,0x00360000,0x003F0000,0x00F70000,0x00CC0000, + 0x00340000,0x00A50000,0x00E50000,0x00F10000,0x00710000,0x00D80000,0x00310000,0x00150000, + 0x00040000,0x00C70000,0x00230000,0x00C30000,0x00180000,0x00960000,0x00050000,0x009A0000, + 0x00070000,0x00120000,0x00800000,0x00E20000,0x00EB0000,0x00270000,0x00B20000,0x00750000, + 0x00090000,0x00830000,0x002C0000,0x001A0000,0x001B0000,0x006E0000,0x005A0000,0x00A00000, + 0x00520000,0x003B0000,0x00D60000,0x00B30000,0x00290000,0x00E30000,0x002F0000,0x00840000, + 0x00530000,0x00D10000,0000000000,0x00ED0000,0x00200000,0x00FC0000,0x00B10000,0x005B0000, + 0x006A0000,0x00CB0000,0x00BE0000,0x00390000,0x004A0000,0x004C0000,0x00580000,0x00CF0000, + 0x00D00000,0x00EF0000,0x00AA0000,0x00FB0000,0x00430000,0x004D0000,0x00330000,0x00850000, + 0x00450000,0x00F90000,0x00020000,0x007F0000,0x00500000,0x003C0000,0x009F0000,0x00A80000, + 0x00510000,0x00A30000,0x00400000,0x008F0000,0x00920000,0x009D0000,0x00380000,0x00F50000, + 0x00BC0000,0x00B60000,0x00DA0000,0x00210000,0x00100000,0x00FF0000,0x00F30000,0x00D20000, + 0x00CD0000,0x000C0000,0x00130000,0x00EC0000,0x005F0000,0x00970000,0x00440000,0x00170000, + 0x00C40000,0x00A70000,0x007E0000,0x003D0000,0x00640000,0x005D0000,0x00190000,0x00730000, + 0x00600000,0x00810000,0x004F0000,0x00DC0000,0x00220000,0x002A0000,0x00900000,0x00880000, + 0x00460000,0x00EE0000,0x00B80000,0x00140000,0x00DE0000,0x005E0000,0x000B0000,0x00DB0000, + 0x00E00000,0x00320000,0x003A0000,0x000A0000,0x00490000,0x00060000,0x00240000,0x005C0000, + 0x00C20000,0x00D30000,0x00AC0000,0x00620000,0x00910000,0x00950000,0x00E40000,0x00790000, + 0x00E70000,0x00C80000,0x00370000,0x006D0000,0x008D0000,0x00D50000,0x004E0000,0x00A90000, + 0x006C0000,0x00560000,0x00F40000,0x00EA0000,0x00650000,0x007A0000,0x00AE0000,0x00080000, + 0x00BA0000,0x00780000,0x00250000,0x002E0000,0x001C0000,0x00A60000,0x00B40000,0x00C60000, + 0x00E80000,0x00DD0000,0x00740000,0x001F0000,0x004B0000,0x00BD0000,0x008B0000,0x008A0000, + 0x00700000,0x003E0000,0x00B50000,0x00660000,0x00480000,0x00030000,0x00F60000,0x000E0000, + 0x00610000,0x00350000,0x00570000,0x00B90000,0x00860000,0x00C10000,0x001D0000,0x009E0000, + 0x00E10000,0x00F80000,0x00980000,0x00110000,0x00690000,0x00D90000,0x008E0000,0x00940000, + 0x009B0000,0x001E0000,0x00870000,0x00E90000,0x00CE0000,0x00550000,0x00280000,0x00DF0000, + 0x008C0000,0x00A10000,0x00890000,0x000D0000,0x00BF0000,0x00E60000,0x00420000,0x00680000, + 0x00410000,0x00990000,0x002D0000,0x000F0000,0x00B00000,0x00540000,0x00BB0000,0x00160000 + }, + { + 0x63000000,0x7C000000,0x77000000,0x7B000000,0xF2000000,0x6B000000,0x6F000000,0xC5000000, + 0x30000000,0x01000000,0x67000000,0x2B000000,0xFE000000,0xD7000000,0xAB000000,0x76000000, + 0xCA000000,0x82000000,0xC9000000,0x7D000000,0xFA000000,0x59000000,0x47000000,0xF0000000, + 0xAD000000,0xD4000000,0xA2000000,0xAF000000,0x9C000000,0xA4000000,0x72000000,0xC0000000, + 0xB7000000,0xFD000000,0x93000000,0x26000000,0x36000000,0x3F000000,0xF7000000,0xCC000000, + 0x34000000,0xA5000000,0xE5000000,0xF1000000,0x71000000,0xD8000000,0x31000000,0x15000000, + 0x04000000,0xC7000000,0x23000000,0xC3000000,0x18000000,0x96000000,0x05000000,0x9A000000, + 0x07000000,0x12000000,0x80000000,0xE2000000,0xEB000000,0x27000000,0xB2000000,0x75000000, + 0x09000000,0x83000000,0x2C000000,0x1A000000,0x1B000000,0x6E000000,0x5A000000,0xA0000000, + 0x52000000,0x3B000000,0xD6000000,0xB3000000,0x29000000,0xE3000000,0x2F000000,0x84000000, + 0x53000000,0xD1000000,0000000000,0xED000000,0x20000000,0xFC000000,0xB1000000,0x5B000000, + 0x6A000000,0xCB000000,0xBE000000,0x39000000,0x4A000000,0x4C000000,0x58000000,0xCF000000, + 0xD0000000,0xEF000000,0xAA000000,0xFB000000,0x43000000,0x4D000000,0x33000000,0x85000000, + 0x45000000,0xF9000000,0x02000000,0x7F000000,0x50000000,0x3C000000,0x9F000000,0xA8000000, + 0x51000000,0xA3000000,0x40000000,0x8F000000,0x92000000,0x9D000000,0x38000000,0xF5000000, + 0xBC000000,0xB6000000,0xDA000000,0x21000000,0x10000000,0xFF000000,0xF3000000,0xD2000000, + 0xCD000000,0x0C000000,0x13000000,0xEC000000,0x5F000000,0x97000000,0x44000000,0x17000000, + 0xC4000000,0xA7000000,0x7E000000,0x3D000000,0x64000000,0x5D000000,0x19000000,0x73000000, + 0x60000000,0x81000000,0x4F000000,0xDC000000,0x22000000,0x2A000000,0x90000000,0x88000000, + 0x46000000,0xEE000000,0xB8000000,0x14000000,0xDE000000,0x5E000000,0x0B000000,0xDB000000, + 0xE0000000,0x32000000,0x3A000000,0x0A000000,0x49000000,0x06000000,0x24000000,0x5C000000, + 0xC2000000,0xD3000000,0xAC000000,0x62000000,0x91000000,0x95000000,0xE4000000,0x79000000, + 0xE7000000,0xC8000000,0x37000000,0x6D000000,0x8D000000,0xD5000000,0x4E000000,0xA9000000, + 0x6C000000,0x56000000,0xF4000000,0xEA000000,0x65000000,0x7A000000,0xAE000000,0x08000000, + 0xBA000000,0x78000000,0x25000000,0x2E000000,0x1C000000,0xA6000000,0xB4000000,0xC6000000, + 0xE8000000,0xDD000000,0x74000000,0x1F000000,0x4B000000,0xBD000000,0x8B000000,0x8A000000, + 0x70000000,0x3E000000,0xB5000000,0x66000000,0x48000000,0x03000000,0xF6000000,0x0E000000, + 0x61000000,0x35000000,0x57000000,0xB9000000,0x86000000,0xC1000000,0x1D000000,0x9E000000, + 0xE1000000,0xF8000000,0x98000000,0x11000000,0x69000000,0xD9000000,0x8E000000,0x94000000, + 0x9B000000,0x1E000000,0x87000000,0xE9000000,0xCE000000,0x55000000,0x28000000,0xDF000000, + 0x8C000000,0xA1000000,0x89000000,0x0D000000,0xBF000000,0xE6000000,0x42000000,0x68000000, + 0x41000000,0x99000000,0x2D000000,0x0F000000,0xB0000000,0x54000000,0xBB000000,0x16000000 + } }; /*----------------- The workspace ------------------------------*/ @@ -432,16 +432,15 @@ void RijndaelKeySchedule(uint8_t key[16]) { uint32_t t; uint32_t *ek=Ekey, /* pointer to the expanded key */ - *rc=rnd_con; /* pointer to the round constant */ + *rc=rnd_con; /* pointer to the round constant */ Ekey[0] = u32_in(key ); Ekey[1] = u32_in(key + 4); Ekey[2] = u32_in(key + 8); Ekey[3] = u32_in(key + 12); - while(ek < Ekey + 40) - { - t = rot3(ek[3]); + while(ek < Ekey + 40) { + t = rot3(ek[3]); ek[4] = ek[0] ^ ls_box(t) ^ *rc++; ek[5] = ek[1] ^ ek[4]; ek[6] = ek[2] ^ ek[5]; @@ -463,18 +462,18 @@ void RijndaelEncrypt(uint8_t in[16], uint8_t out[16]) b0[2] = u32_in(in + 8) ^ *kp++; b0[3] = u32_in(in + 12) ^ *kp++; - f_round(b1, b0, kp); + f_round(b1, b0, kp); f_round(b0, b1, kp); - f_round(b1, b0, kp); + f_round(b1, b0, kp); f_round(b0, b1, kp); - f_round(b1, b0, kp); + f_round(b1, b0, kp); f_round(b0, b1, kp); - f_round(b1, b0, kp); + f_round(b1, b0, kp); f_round(b0, b1, kp); - f_round(b1, b0, kp); + f_round(b1, b0, kp); - u32_out(out, lf_rnd(b1, 0) ^ kp[0]); + u32_out(out, lf_rnd(b1, 0) ^ kp[0]); u32_out(out + 4, lf_rnd(b1, 1) ^ kp[1]); - u32_out(out + 8, lf_rnd(b1, 2) ^ kp[2]); + u32_out(out + 8, lf_rnd(b1, 2) ^ kp[2]); u32_out(out + 12, lf_rnd(b1, 3) ^ kp[3]); } diff --git a/tinySIP/src/dialogs/tsip_dialog.c b/tinySIP/src/dialogs/tsip_dialog.c index 13dcdf4..3f23f0e 100755 --- a/tinySIP/src/dialogs/tsip_dialog.c +++ b/tinySIP/src/dialogs/tsip_dialog.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 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. * @@ -87,363 +87,361 @@ extern tsip_uri_t* tsip_stack_get_contacturi(const tsip_stack_t *self, const cha tsip_request_t *tsip_dialog_request_new(const tsip_dialog_t *self, const char* method) { - tsip_request_t *request = tsk_null; - tsip_uri_t *to_uri, *from_uri, *request_uri; - const char *call_id; - int copy_routes_start = -1; /* NONE */ - const tsk_list_item_t* item; - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - The Call-ID of the request MUST be set to the Call-ID of the dialog. - */ - call_id = self->callid; - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - Requests within a dialog MUST contain strictly monotonically - increasing and contiguous CSeq sequence numbers (increasing-by-one) - in each direction (excepting ACK and CANCEL of course, whose numbers - equal the requests being acknowledged or cancelled). Therefore, if - the local sequence number is not empty, the value of the local - sequence number MUST be incremented by one, and this value MUST be - placed into the CSeq header field. - */ - /*if(!tsk_striequals(method, "ACK") && !tsk_striequals(method, "CANCEL")) - { - TSIP_DIALOG(self)->cseq_value +=1; - } - ===> See send method (cseq will be incremented before sending the request) - */ - - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - The URI in the To field of the request MUST be set to the remote URI - from the dialog state. The tag in the To header field of the request - MUST be set to the remote tag of the dialog ID. The From URI of the - request MUST be set to the local URI from the dialog state. The tag - in the From header field of the request MUST be set to the local tag - of the dialog ID. If the value of the remote or local tags is null, - the tag parameter MUST be omitted from the To or From header fields, - respectively. - */ - to_uri = tsk_object_ref((void*)self->uri_remote); - from_uri = tsk_object_ref((void*)self->uri_local); - - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - If the route set is empty, the UAC MUST place the remote target URI - into the Request-URI. The UAC MUST NOT add a Route header field to - the request. - */ - if(TSK_LIST_IS_EMPTY(self->record_routes)){ - request_uri = tsk_object_ref((void*)self->uri_remote_target); - } - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - If the route set is not empty, and the first URI in the route set - contains the lr parameter (see Section 19.1.1), the UAC MUST place - the remote target URI into the Request-URI and MUST include a Route - header field containing the route set values in order, including all - parameters. - - If the route set is not empty, and its first URI does not contain the - lr parameter, the UAC MUST place the first URI from the route set - into the Request-URI, stripping any parameters that are not allowed - in a Request-URI. The UAC MUST add a Route header field containing - the remainder of the route set values in order, including all - parameters. The UAC MUST then place the remote target URI into the - Route header field as the last value. - - For example, if the remote target is sip:user@remoteua and the route - set contains: - - <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4> - */ - else{ - const tsip_uri_t *first_route = ((tsip_header_Record_Route_t*)TSK_LIST_FIRST_DATA(self->record_routes))->uri; - if(tsk_params_have_param(first_route->params, "lr")){ - request_uri = tsk_object_ref(self->uri_remote_target); - copy_routes_start = 0; /* Copy all */ - } - else{ - request_uri = tsk_object_ref((void*)first_route); - copy_routes_start = 1; /* Copy starting at index 1. */ - } - } - - /*===================================================================== - */ - request = tsip_request_new(method, request_uri, from_uri, to_uri, call_id, self->cseq_value); - request->To->tag = tsk_strdup(self->tag_remote); - request->From->tag = tsk_strdup(self->tag_local); - request->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact, SigComp, IPSec, ...) */ - - - /* - RFC 3261 - 12.2.1.1 Generating the Request - - A UAC SHOULD include a Contact header field in any target refresh - requests within a dialog, and unless there is a need to change it, - the URI SHOULD be the same as used in previous requests within the - dialog. If the "secure" flag is true, that URI MUST be a SIPS URI. - As discussed in Section 12.2.2, a Contact header field in a target - refresh request updates the remote target URI. This allows a UA to - provide a new contact address, should its address change during the - duration of the dialog. - */ - switch(request->line.request.request_type){ - case tsip_MESSAGE: - case tsip_PUBLISH: - case tsip_BYE: - { - if(request->line.request.request_type == tsip_PUBLISH) { - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires))); - } - /* add caps in Accept-Contact headers */ - tsk_list_foreach(item, self->ss->caps) { - const tsk_param_t* param = TSK_PARAM(item->data); - char* value = tsk_null; - tsk_sprintf(&value, "*;%s%s%s", - param->name, - param->value ? "=" : "", - param->value ? param->value : ""); - if(value) { - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Accept-Contact", value)); - TSK_FREE(value); - } - } - break; - } - - default: - { - char* contact = tsk_null; - tsip_header_Contacts_L_t *hdr_contacts; - - if(request->line.request.request_type == tsip_OPTIONS || - request->line.request.request_type == tsip_PUBLISH || - request->line.request.request_type == tsip_REGISTER){ - /**** with expires */ - tsk_sprintf(&contact, "m: <%s:%s@%s:%d>;expires=%d\r\n", - "sip", - from_uri->user_name, - "127.0.0.1", - 5060, - - TSK_TIME_MS_2_S(self->expires)); - } - else{ - /**** without expires */ - if(request->line.request.request_type == tsip_SUBSCRIBE){ - /* RFC 3265 - 3.1.1. Subscription Duration - An "expires" parameter on the "Contact" header has no semantics for SUBSCRIBE and is explicitly - not equivalent to an "Expires" header in a SUBSCRIBE request or response. - */ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires))); - } - tsk_sprintf(&contact, "m: <%s:%s@%s:%d%s%s%s%s%s%s%s%s%s>\r\n", - "sip", - from_uri->user_name, - "127.0.0.1", - 5060, - - self->ss->ws.src.host ? ";" : "", - self->ss->ws.src.host ? "ws-src-ip=" : "", - self->ss->ws.src.host ? self->ss->ws.src.host : "", - self->ss->ws.src.port[0] ? ";" : "", - self->ss->ws.src.port[0] ? "ws-src-port=" : "", - self->ss->ws.src.port[0] ? self->ss->ws.src.port : "", - self->ss->ws.src.proto ? ";" : "", - self->ss->ws.src.proto ? "ws-src-proto=" : "", - self->ss->ws.src.proto ? self->ss->ws.src.proto : "" - ); - } - hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact)); - if(!TSK_LIST_IS_EMPTY(hdr_contacts)){ - request->Contact = tsk_object_ref(hdr_contacts->head->data); - } - TSK_OBJECT_SAFE_FREE(hdr_contacts); - TSK_FREE(contact); - - /* Add capabilities as per RFC 3840 */ - if(request->Contact) { - tsk_list_foreach(item, self->ss->caps){ - tsk_params_add_param(&TSIP_HEADER(request->Contact)->params, TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value); - } - } - - break; - } - } - - /* Update authorizations */ - if(self->state == tsip_initial && TSK_LIST_IS_EMPTY(self->challenges)){ - /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE - On sending a REGISTER request in order to indicate support for early IMS security procedures, the UE shall not - include an Authorization header field and not include header fields or header field values as required by RFC3329. - */ - if(TSIP_REQUEST_IS_REGISTER(request) && !TSIP_DIALOG_GET_STACK(self)->security.earlyIMS){ - /* 3GPP TS 24.229 - 5.1.1.2.2 Initial registration using IMS AKA - On sending a REGISTER request, the UE shall populate the header fields as follows: - a) an Authorization header field, with: - - the "username" header field parameter, set to the value of the private user identity; - - the "realm" header field parameter, set to the domain name of the home network; - - the "uri" header field parameter, set to the SIP URI of the domain name of the home network; - - the "nonce" header field parameter, set to an empty value; and - - the "response" header field parameter, set to an empty value; - */ - const char* realm = TSIP_DIALOG_GET_STACK(self)->network.realm ? TSIP_DIALOG_GET_STACK(self)->network.realm->host : "(null)"; - char* request_uri = tsip_uri_tostring(request->line.request.uri, tsk_false, tsk_false); - tsip_header_t* auth_hdr = tsip_challenge_create_empty_header_authorization(TSIP_DIALOG_GET_STACK(self)->identity.impi, realm, request_uri); - tsip_message_add_header(request, auth_hdr); - tsk_object_unref(auth_hdr), auth_hdr = tsk_null; - TSK_FREE(request_uri); - } - } - else if(!TSK_LIST_IS_EMPTY(self->challenges)){ - tsip_challenge_t *challenge; - tsip_header_t* auth_hdr; - tsk_list_foreach(item, self->challenges){ - challenge = item->data; - auth_hdr = tsip_challenge_create_header_authorization(challenge, request); - if(auth_hdr){ - tsip_message_add_header(request, auth_hdr); - tsk_object_unref(auth_hdr), auth_hdr = tsk_null; - } - } - } - - /* Update CSeq */ - /* RFC 3261 - 13.2.2.4 2xx Responses - Generating ACK: The sequence number of the CSeq header field MUST be - the same as the INVITE being acknowledged, but the CSeq method MUST - be ACK. The ACK MUST contain the same credentials as the INVITE. If - the 2xx contains an offer (based on the rules above), the ACK MUST - carry an answer in its body. - ==> CSeq number will be added/updated by the caller of this function, - credentials were added above. - */ - if(!TSIP_REQUEST_IS_ACK(request) && !TSIP_REQUEST_IS_CANCEL(request)){ - request->CSeq->seq = ++(TSIP_DIALOG(self)->cseq_value); - } - - /* Route generation - * ==> http://betelco.blogspot.com/2008/11/proxy-and-service-route-discovery-in.html - * The dialog Routes have been copied above. - - 3GPP TS 24.229 - 5.1.2A.1 UE-originating case - - The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE - shall build a list of Route header field values made out of the following, in this order: - a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and - b) the P-CSCF port based on the security mechanism in use: - - - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during - the registration procedure; - - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in - use as a security mechanism, the unprotected server port used during the registration procedure; - c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last - registration or re-registration of the public user identity with associated contact address. - */ - if(!TSIP_REQUEST_IS_REGISTER(request)) - { // According to the above link ==> Initial/Re/De registration do not have routes. - if(copy_routes_start != -1) - { /* The dialog already have routes ==> copy them. */ - if(self->state == tsip_early || self->state == tsip_established){ - int32_t index = -1; - tsk_list_foreach(item, self->record_routes){ - tsip_header_Record_Route_t *record_Route = ((tsip_header_Record_Route_t*)item->data); - const tsip_uri_t* uri = record_Route->uri; - tsip_header_Route_t *route = tsk_null; - if(++index < copy_routes_start || !uri){ - continue; - } - - if((route = tsip_header_Route_create(uri))){ - // copy parameters: see http://code.google.com/p/imsdroid/issues/detail?id=52 - if(!TSK_LIST_IS_EMPTY(TSIP_HEADER_PARAMS(record_Route))){ - if(!TSIP_HEADER_PARAMS(route)){ - TSIP_HEADER_PARAMS(route) = tsk_list_create(); - } - tsk_list_pushback_list(TSIP_HEADER_PARAMS(route), TSIP_HEADER_PARAMS(record_Route)); - } - - tsip_message_add_header(request, TSIP_HEADER(route)); - TSK_OBJECT_SAFE_FREE(route); - } - } - } - } - else - { /* No routes associated to this dialog. */ - if(self->state == tsip_initial || self->state == tsip_early){ - /* GPP TS 24.229 section 5.1.2A [Generic procedures applicable to all methods excluding the REGISTER method]: - The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE - shall build a list of Route header field values made out of the following, in this order: - a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and - b) the P-CSCF port based on the security mechanism in use: - - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during - the registration procedure; - - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in - use as a security mechanism, the unprotected server port used during the registration procedure; - c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last - registration or re-registration of the public user identity with associated contact address. - */ + tsip_request_t *request = tsk_null; + tsip_uri_t *to_uri, *from_uri, *request_uri; + const char *call_id; + int copy_routes_start = -1; /* NONE */ + const tsk_list_item_t* item; + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + The Call-ID of the request MUST be set to the Call-ID of the dialog. + */ + call_id = self->callid; + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + Requests within a dialog MUST contain strictly monotonically + increasing and contiguous CSeq sequence numbers (increasing-by-one) + in each direction (excepting ACK and CANCEL of course, whose numbers + equal the requests being acknowledged or cancelled). Therefore, if + the local sequence number is not empty, the value of the local + sequence number MUST be incremented by one, and this value MUST be + placed into the CSeq header field. + */ + /*if(!tsk_striequals(method, "ACK") && !tsk_striequals(method, "CANCEL")) + { + TSIP_DIALOG(self)->cseq_value +=1; + } + ===> See send method (cseq will be incremented before sending the request) + */ + + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + The URI in the To field of the request MUST be set to the remote URI + from the dialog state. The tag in the To header field of the request + MUST be set to the remote tag of the dialog ID. The From URI of the + request MUST be set to the local URI from the dialog state. The tag + in the From header field of the request MUST be set to the local tag + of the dialog ID. If the value of the remote or local tags is null, + the tag parameter MUST be omitted from the To or From header fields, + respectively. + */ + to_uri = tsk_object_ref((void*)self->uri_remote); + from_uri = tsk_object_ref((void*)self->uri_local); + + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + If the route set is empty, the UAC MUST place the remote target URI + into the Request-URI. The UAC MUST NOT add a Route header field to + the request. + */ + if(TSK_LIST_IS_EMPTY(self->record_routes)) { + request_uri = tsk_object_ref((void*)self->uri_remote_target); + } + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + If the route set is not empty, and the first URI in the route set + contains the lr parameter (see Section 19.1.1), the UAC MUST place + the remote target URI into the Request-URI and MUST include a Route + header field containing the route set values in order, including all + parameters. + + If the route set is not empty, and its first URI does not contain the + lr parameter, the UAC MUST place the first URI from the route set + into the Request-URI, stripping any parameters that are not allowed + in a Request-URI. The UAC MUST add a Route header field containing + the remainder of the route set values in order, including all + parameters. The UAC MUST then place the remote target URI into the + Route header field as the last value. + + For example, if the remote target is sip:user@remoteua and the route + set contains: + + <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4> + */ + else { + const tsip_uri_t *first_route = ((tsip_header_Record_Route_t*)TSK_LIST_FIRST_DATA(self->record_routes))->uri; + if(tsk_params_have_param(first_route->params, "lr")) { + request_uri = tsk_object_ref(self->uri_remote_target); + copy_routes_start = 0; /* Copy all */ + } + else { + request_uri = tsk_object_ref((void*)first_route); + copy_routes_start = 1; /* Copy starting at index 1. */ + } + } + + /*===================================================================== + */ + request = tsip_request_new(method, request_uri, from_uri, to_uri, call_id, self->cseq_value); + request->To->tag = tsk_strdup(self->tag_remote); + request->From->tag = tsk_strdup(self->tag_local); + request->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact, SigComp, IPSec, ...) */ + + + /* + RFC 3261 - 12.2.1.1 Generating the Request + + A UAC SHOULD include a Contact header field in any target refresh + requests within a dialog, and unless there is a need to change it, + the URI SHOULD be the same as used in previous requests within the + dialog. If the "secure" flag is true, that URI MUST be a SIPS URI. + As discussed in Section 12.2.2, a Contact header field in a target + refresh request updates the remote target URI. This allows a UA to + provide a new contact address, should its address change during the + duration of the dialog. + */ + switch(request->line.request.request_type) { + case tsip_MESSAGE: + case tsip_PUBLISH: + case tsip_BYE: { + if(request->line.request.request_type == tsip_PUBLISH) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires))); + } + /* add caps in Accept-Contact headers */ + tsk_list_foreach(item, self->ss->caps) { + const tsk_param_t* param = TSK_PARAM(item->data); + char* value = tsk_null; + tsk_sprintf(&value, "*;%s%s%s", + param->name, + param->value ? "=" : "", + param->value ? param->value : ""); + if(value) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Accept-Contact", value)); + TSK_FREE(value); + } + } + break; + } + + default: { + char* contact = tsk_null; + tsip_header_Contacts_L_t *hdr_contacts; + + if(request->line.request.request_type == tsip_OPTIONS || + request->line.request.request_type == tsip_PUBLISH || + request->line.request.request_type == tsip_REGISTER) { + /**** with expires */ + tsk_sprintf(&contact, "m: <%s:%s@%s:%d>;expires=%d\r\n", + "sip", + from_uri->user_name, + "127.0.0.1", + 5060, + + TSK_TIME_MS_2_S(self->expires)); + } + else { + /**** without expires */ + if(request->line.request.request_type == tsip_SUBSCRIBE) { + /* RFC 3265 - 3.1.1. Subscription Duration + An "expires" parameter on the "Contact" header has no semantics for SUBSCRIBE and is explicitly + not equivalent to an "Expires" header in a SUBSCRIBE request or response. + */ + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires))); + } + tsk_sprintf(&contact, "m: <%s:%s@%s:%d%s%s%s%s%s%s%s%s%s>\r\n", + "sip", + from_uri->user_name, + "127.0.0.1", + 5060, + + self->ss->ws.src.host ? ";" : "", + self->ss->ws.src.host ? "ws-src-ip=" : "", + self->ss->ws.src.host ? self->ss->ws.src.host : "", + self->ss->ws.src.port[0] ? ";" : "", + self->ss->ws.src.port[0] ? "ws-src-port=" : "", + self->ss->ws.src.port[0] ? self->ss->ws.src.port : "", + self->ss->ws.src.proto ? ";" : "", + self->ss->ws.src.proto ? "ws-src-proto=" : "", + self->ss->ws.src.proto ? self->ss->ws.src.proto : "" + ); + } + hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact)); + if(!TSK_LIST_IS_EMPTY(hdr_contacts)) { + request->Contact = tsk_object_ref(hdr_contacts->head->data); + } + TSK_OBJECT_SAFE_FREE(hdr_contacts); + TSK_FREE(contact); + + /* Add capabilities as per RFC 3840 */ + if(request->Contact) { + tsk_list_foreach(item, self->ss->caps) { + tsk_params_add_param(&TSIP_HEADER(request->Contact)->params, TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value); + } + } + + break; + } + } + + /* Update authorizations */ + if(self->state == tsip_initial && TSK_LIST_IS_EMPTY(self->challenges)) { + /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE + On sending a REGISTER request in order to indicate support for early IMS security procedures, the UE shall not + include an Authorization header field and not include header fields or header field values as required by RFC3329. + */ + if(TSIP_REQUEST_IS_REGISTER(request) && !TSIP_DIALOG_GET_STACK(self)->security.earlyIMS) { + /* 3GPP TS 24.229 - 5.1.1.2.2 Initial registration using IMS AKA + On sending a REGISTER request, the UE shall populate the header fields as follows: + a) an Authorization header field, with: + - the "username" header field parameter, set to the value of the private user identity; + - the "realm" header field parameter, set to the domain name of the home network; + - the "uri" header field parameter, set to the SIP URI of the domain name of the home network; + - the "nonce" header field parameter, set to an empty value; and + - the "response" header field parameter, set to an empty value; + */ + const char* realm = TSIP_DIALOG_GET_STACK(self)->network.realm ? TSIP_DIALOG_GET_STACK(self)->network.realm->host : "(null)"; + char* request_uri = tsip_uri_tostring(request->line.request.uri, tsk_false, tsk_false); + tsip_header_t* auth_hdr = tsip_challenge_create_empty_header_authorization(TSIP_DIALOG_GET_STACK(self)->identity.impi, realm, request_uri); + tsip_message_add_header(request, auth_hdr); + tsk_object_unref(auth_hdr), auth_hdr = tsk_null; + TSK_FREE(request_uri); + } + } + else if(!TSK_LIST_IS_EMPTY(self->challenges)) { + tsip_challenge_t *challenge; + tsip_header_t* auth_hdr; + tsk_list_foreach(item, self->challenges) { + challenge = item->data; + auth_hdr = tsip_challenge_create_header_authorization(challenge, request); + if(auth_hdr) { + tsip_message_add_header(request, auth_hdr); + tsk_object_unref(auth_hdr), auth_hdr = tsk_null; + } + } + } + + /* Update CSeq */ + /* RFC 3261 - 13.2.2.4 2xx Responses + Generating ACK: The sequence number of the CSeq header field MUST be + the same as the INVITE being acknowledged, but the CSeq method MUST + be ACK. The ACK MUST contain the same credentials as the INVITE. If + the 2xx contains an offer (based on the rules above), the ACK MUST + carry an answer in its body. + ==> CSeq number will be added/updated by the caller of this function, + credentials were added above. + */ + if(!TSIP_REQUEST_IS_ACK(request) && !TSIP_REQUEST_IS_CANCEL(request)) { + request->CSeq->seq = ++(TSIP_DIALOG(self)->cseq_value); + } + + /* Route generation + * ==> http://betelco.blogspot.com/2008/11/proxy-and-service-route-discovery-in.html + * The dialog Routes have been copied above. + + 3GPP TS 24.229 - 5.1.2A.1 UE-originating case + + The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE + shall build a list of Route header field values made out of the following, in this order: + a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and + b) the P-CSCF port based on the security mechanism in use: + + - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during + the registration procedure; + - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in + use as a security mechanism, the unprotected server port used during the registration procedure; + c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last + registration or re-registration of the public user identity with associated contact address. + */ + if(!TSIP_REQUEST_IS_REGISTER(request)) { + // According to the above link ==> Initial/Re/De registration do not have routes. + if(copy_routes_start != -1) { + /* The dialog already have routes ==> copy them. */ + if(self->state == tsip_early || self->state == tsip_established) { + int32_t index = -1; + tsk_list_foreach(item, self->record_routes) { + tsip_header_Record_Route_t *record_Route = ((tsip_header_Record_Route_t*)item->data); + const tsip_uri_t* uri = record_Route->uri; + tsip_header_Route_t *route = tsk_null; + if(++index < copy_routes_start || !uri) { + continue; + } + + if((route = tsip_header_Route_create(uri))) { + // copy parameters: see http://code.google.com/p/imsdroid/issues/detail?id=52 + if(!TSK_LIST_IS_EMPTY(TSIP_HEADER_PARAMS(record_Route))) { + if(!TSIP_HEADER_PARAMS(route)) { + TSIP_HEADER_PARAMS(route) = tsk_list_create(); + } + tsk_list_pushback_list(TSIP_HEADER_PARAMS(route), TSIP_HEADER_PARAMS(record_Route)); + } + + tsip_message_add_header(request, TSIP_HEADER(route)); + TSK_OBJECT_SAFE_FREE(route); + } + } + } + } + else { + /* No routes associated to this dialog. */ + if(self->state == tsip_initial || self->state == tsip_early) { + /* GPP TS 24.229 section 5.1.2A [Generic procedures applicable to all methods excluding the REGISTER method]: + The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE + shall build a list of Route header field values made out of the following, in this order: + a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and + b) the P-CSCF port based on the security mechanism in use: + - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during + the registration procedure; + - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in + use as a security mechanism, the unprotected server port used during the registration procedure; + c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last + registration or re-registration of the public user identity with associated contact address. + */ #if _DEBUG && defined(SDS_HACK)/* FIXME: remove this */ - /* Ericsson SDS hack (INVITE with Proxy-CSCF as First route fail) */ + /* Ericsson SDS hack (INVITE with Proxy-CSCF as First route fail) */ #elif 0 - tsip_uri_t *uri = tsip_stack_get_pcscf_uri(TSIP_DIALOG_GET_STACK(self), tsk_true); - // Proxy-CSCF as first route - if(uri){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(uri)); - TSK_OBJECT_SAFE_FREE(uri); - } + tsip_uri_t *uri = tsip_stack_get_pcscf_uri(TSIP_DIALOG_GET_STACK(self), tsk_true); + // Proxy-CSCF as first route + if(uri) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(uri)); + TSK_OBJECT_SAFE_FREE(uri); + } #endif - // Service routes - tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->service_routes){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(item->data)); - } - } - } - } - - /* Add headers associated to the session */ - tsip_dialog_add_session_headers(self, request); - - /* Add headers associated to the dialog's stack */ - TSIP_DIALOG_ADD_HEADERS(self->ss->stack->headers); - - /* Add common headers */ - tsip_dialog_add_common_headers(self, request); - - /* SigComp */ - if(self->ss->sigcomp_id){ - /* should be added in this field instead of 'Contact' or 'Via' headers - * it's up to the transport layer to copy it to these headers */ - request->sigcomp_id = tsk_strdup(self->ss->sigcomp_id); - } - - /* Remote Address: Used if "Server mode" otherwise Proxy-CSCF will be used */ - request->remote_addr = self->remote_addr; - /* Connected FD */ - if(request->local_fd <= 0) { - request->local_fd = self->connected_fd; - } - - TSK_OBJECT_SAFE_FREE(request_uri); - TSK_OBJECT_SAFE_FREE(from_uri); - TSK_OBJECT_SAFE_FREE(to_uri); - - return request; + // Service routes + tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->service_routes) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(item->data)); + } + } + } + } + + /* Add headers associated to the session */ + tsip_dialog_add_session_headers(self, request); + + /* Add headers associated to the dialog's stack */ + TSIP_DIALOG_ADD_HEADERS(self->ss->stack->headers); + + /* Add common headers */ + tsip_dialog_add_common_headers(self, request); + + /* SigComp */ + if(self->ss->sigcomp_id) { + /* should be added in this field instead of 'Contact' or 'Via' headers + * it's up to the transport layer to copy it to these headers */ + request->sigcomp_id = tsk_strdup(self->ss->sigcomp_id); + } + + /* Remote Address: Used if "Server mode" otherwise Proxy-CSCF will be used */ + request->remote_addr = self->remote_addr; + /* Connected FD */ + if(request->local_fd <= 0) { + request->local_fd = self->connected_fd; + } + + TSK_OBJECT_SAFE_FREE(request_uri); + TSK_OBJECT_SAFE_FREE(from_uri); + TSK_OBJECT_SAFE_FREE(to_uri); + + return request; } @@ -452,156 +450,155 @@ tsip_request_t *tsip_dialog_request_new(const tsip_dialog_t *self, const char* m * @param self The parent dialog. All callback events will be notified to this dialog. * @param request The request to send. * - * @return Zero if succeed and no-zero error code otherwise. + * @return Zero if succeed and no-zero error code otherwise. **/ int tsip_dialog_request_send(const tsip_dialog_t *self, tsip_request_t* request) { - int ret = -1; - - if(self && TSIP_DIALOG_GET_STACK(self)){ - const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac; - if(layer){ - /* Create new transaction. The new transaction will be added to the transaction layer. - The transaction has all information to create the right transaction type (NICT or ICT). - As this is an outgoing request ==> It shall be a client transaction (NICT or ICT). - For server transactions creation see @ref tsip_dialog_response_send. - */ - static const tsk_bool_t isCT = tsk_true; - tsip_transac_t* transac; - tsip_transac_dst_t* dst; - - - if(TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))){ - const tsip_transport_t* transport = tsip_transport_layer_find_by_idx(TSIP_DIALOG_GET_STACK(self)->layer_transport, TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default); - if(!transport){ - TSK_DEBUG_ERROR("Failed to find a valid default transport [%d]", TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default); - } - else{ - request->dst_net_type = transport->type; - } - } - dst = tsip_transac_dst_dialog_create(TSIP_DIALOG(self)); - transac = tsip_transac_layer_new( - layer, - isCT, - request, - dst - ); - TSK_OBJECT_SAFE_FREE(dst); - - /* Set the transaction's dialog. All events comming from the transaction (timeouts, errors ...) will be signaled to this dialog */ - if(transac){ - switch(transac->type) - { - case tsip_transac_type_ict: - case tsip_transac_type_nict: - { - /* Start the newly create IC/NIC transaction */ - ret = tsip_transac_start(transac, request); - break; - } - default: break; - } - TSK_OBJECT_SAFE_FREE(transac); - } - } - } - return ret; + int ret = -1; + + if(self && TSIP_DIALOG_GET_STACK(self)) { + const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac; + if(layer) { + /* Create new transaction. The new transaction will be added to the transaction layer. + The transaction has all information to create the right transaction type (NICT or ICT). + As this is an outgoing request ==> It shall be a client transaction (NICT or ICT). + For server transactions creation see @ref tsip_dialog_response_send. + */ + static const tsk_bool_t isCT = tsk_true; + tsip_transac_t* transac; + tsip_transac_dst_t* dst; + + + if(TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))) { + const tsip_transport_t* transport = tsip_transport_layer_find_by_idx(TSIP_DIALOG_GET_STACK(self)->layer_transport, TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default); + if(!transport) { + TSK_DEBUG_ERROR("Failed to find a valid default transport [%d]", TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default); + } + else { + request->dst_net_type = transport->type; + } + } + dst = tsip_transac_dst_dialog_create(TSIP_DIALOG(self)); + transac = tsip_transac_layer_new( + layer, + isCT, + request, + dst + ); + TSK_OBJECT_SAFE_FREE(dst); + + /* Set the transaction's dialog. All events comming from the transaction (timeouts, errors ...) will be signaled to this dialog */ + if(transac) { + switch(transac->type) { + case tsip_transac_type_ict: + case tsip_transac_type_nict: { + /* Start the newly create IC/NIC transaction */ + ret = tsip_transac_start(transac, request); + break; + } + default: + break; + } + TSK_OBJECT_SAFE_FREE(transac); + } + } + } + return ret; } tsip_response_t *tsip_dialog_response_new(tsip_dialog_t *self, short status, const char* phrase, const tsip_request_t* request) { - /* Reponse is created as per RFC 3261 subclause 8.2.6 and (headers+tags) are copied - * as per subclause 8.2.6.2. - */ - tsip_response_t* response; - if((response = tsip_response_new(status, phrase, request))){ - switch(request->line.request.request_type){ - case tsip_MESSAGE: - case tsip_PUBLISH: - break; - default: - /* Is there a To tag? */ - if(response->To && !response->To->tag){ - response->To->tag = tsk_strdup(self->tag_local); - } - /* Contact Header (for 101-299 reponses) */ - if(self->uri_local && TSIP_RESPONSE_CODE(response) >= 101 && TSIP_RESPONSE_CODE(response) <= 299){ - char* contact = tsk_null; - tsip_header_Contacts_L_t *hdr_contacts; - - tsk_sprintf(&contact, "m: <%s:%s@%s:%d>\r\n", "sip", self->uri_local->user_name, "127.0.0.1", 5060); - hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact)); - if(!TSK_LIST_IS_EMPTY(hdr_contacts)){ - response->Contact = tsk_object_ref(hdr_contacts->head->data); - response->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact header) */ - } - TSK_OBJECT_SAFE_FREE(hdr_contacts); - TSK_FREE(contact); - } - break; - } - - /* SigComp */ - if(self->ss->sigcomp_id){ - /* should be added in this field instead of 'Contact' or 'Via' headers - * it's up to the transport layer to copy it to these headers */ - response->sigcomp_id = tsk_strdup(self->ss->sigcomp_id); - } - /* Connected FD */ - if(response->local_fd <= 0) { - response->local_fd = self->connected_fd; - } - /* Remote Addr: used to send requests if "Server Mode" otherwise Proxy-CSCF address will be used */ - self->remote_addr = request->remote_addr; - } - return response; + /* Reponse is created as per RFC 3261 subclause 8.2.6 and (headers+tags) are copied + * as per subclause 8.2.6.2. + */ + tsip_response_t* response; + if((response = tsip_response_new(status, phrase, request))) { + switch(request->line.request.request_type) { + case tsip_MESSAGE: + case tsip_PUBLISH: + break; + default: + /* Is there a To tag? */ + if(response->To && !response->To->tag) { + response->To->tag = tsk_strdup(self->tag_local); + } + /* Contact Header (for 101-299 reponses) */ + if(self->uri_local && TSIP_RESPONSE_CODE(response) >= 101 && TSIP_RESPONSE_CODE(response) <= 299) { + char* contact = tsk_null; + tsip_header_Contacts_L_t *hdr_contacts; + + tsk_sprintf(&contact, "m: <%s:%s@%s:%d>\r\n", "sip", self->uri_local->user_name, "127.0.0.1", 5060); + hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact)); + if(!TSK_LIST_IS_EMPTY(hdr_contacts)) { + response->Contact = tsk_object_ref(hdr_contacts->head->data); + response->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact header) */ + } + TSK_OBJECT_SAFE_FREE(hdr_contacts); + TSK_FREE(contact); + } + break; + } + + /* SigComp */ + if(self->ss->sigcomp_id) { + /* should be added in this field instead of 'Contact' or 'Via' headers + * it's up to the transport layer to copy it to these headers */ + response->sigcomp_id = tsk_strdup(self->ss->sigcomp_id); + } + /* Connected FD */ + if(response->local_fd <= 0) { + response->local_fd = self->connected_fd; + } + /* Remote Addr: used to send requests if "Server Mode" otherwise Proxy-CSCF address will be used */ + self->remote_addr = request->remote_addr; + } + return response; } int tsip_dialog_response_send(const tsip_dialog_t *self, tsip_response_t* response) { - int ret = -1; - - if(self && TSIP_DIALOG_GET_STACK(self)){ - const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac; - if(layer){ - /* As this is a response ...then use the associate server transaction */ - tsip_transac_t *transac = tsip_transac_layer_find_server(layer, response); - if(transac){ - ret = transac->callback(transac, tsip_transac_outgoing_msg, response); - tsk_object_unref(transac); - } - else{ - TSK_DEBUG_ERROR("Failed to find associated server transaction."); - // Send "408 Request Timeout" (should be done by the transaction layer)? - } - } - } - else{ - TSK_DEBUG_ERROR("Invalid parameter"); - } - return ret; + int ret = -1; + + if(self && TSIP_DIALOG_GET_STACK(self)) { + const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac; + if(layer) { + /* As this is a response ...then use the associate server transaction */ + tsip_transac_t *transac = tsip_transac_layer_find_server(layer, response); + if(transac) { + ret = transac->callback(transac, tsip_transac_outgoing_msg, response); + tsk_object_unref(transac); + } + else { + TSK_DEBUG_ERROR("Failed to find associated server transaction."); + // Send "408 Request Timeout" (should be done by the transaction layer)? + } + } + } + else { + TSK_DEBUG_ERROR("Invalid parameter"); + } + return ret; } int tsip_dialog_apply_action(tsip_message_t* message, const tsip_action_t* action) { - const tsk_list_item_t* item; - - if(!message || !action){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* SIP headers */ - tsk_list_foreach(item, action->headers){ - TSIP_MESSAGE_ADD_HEADER(message, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); - } - /* Payload */ - if(action->payload){ - tsip_message_add_content(message, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload)); - } - - return 0; + const tsk_list_item_t* item; + + if(!message || !action) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + /* SIP headers */ + tsk_list_foreach(item, action->headers) { + TSIP_MESSAGE_ADD_HEADER(message, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); + } + /* Payload */ + if(action->payload) { + tsip_message_add_content(message, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload)); + } + + return 0; } /** @@ -612,72 +609,69 @@ int tsip_dialog_apply_action(tsip_message_t* message, const tsip_action_t* actio * @param [in,out] self The calling dialog. * @param [in,out] response The SIP/IMS response containing the new delay (expires, subscription-state ...). * - * @return Zero if succeed and no-zero error code otherwise. + * @return Zero if succeed and no-zero error code otherwise. **/ int64_t tsip_dialog_get_newdelay(tsip_dialog_t *self, const tsip_message_t* message) { - int64_t expires = self->expires; - int64_t newdelay = expires; /* default value */ - const tsip_header_t* hdr; - tsk_size_t i; - - /*== NOTIFY with subscription-state header with expires parameter. - */ - if(TSIP_REQUEST_IS_NOTIFY(message)){ - const tsip_header_Subscription_State_t *hdr_state; - if((hdr_state = (const tsip_header_Subscription_State_t*)tsip_message_get_header(message, tsip_htype_Subscription_State))){ - if(hdr_state->expires >0){ - expires = TSK_TIME_S_2_MS(hdr_state->expires); - goto compute; - } - } - } - - /*== Expires header. - */ - if((hdr = tsip_message_get_header(message, tsip_htype_Expires))){ - expires = TSK_TIME_S_2_MS(((const tsip_header_Expires_t*)hdr)->delta_seconds); - goto compute; - } - - /*== Contact header. - */ - for(i=0; (hdr = tsip_message_get_headerAt(message, tsip_htype_Contact, i)); i++){ - const tsip_header_Contact_t* contact = (const tsip_header_Contact_t*)hdr; - if(contact && contact->uri) - { - const char* transport = tsk_params_get_param_value(contact->uri->params, "transport"); - tsip_uri_t* contactUri = tsip_stack_get_contacturi(TSIP_DIALOG_GET_STACK(self), transport ? transport : "udp"); - if(contactUri) - { - if(tsk_strequals(contact->uri->user_name, contactUri->user_name) - && tsk_strequals(contact->uri->host, contactUri->host) - && contact->uri->port == contactUri->port) - { - if(contact->expires>=0){ /* No expires parameter ==> -1*/ - expires = TSK_TIME_S_2_MS(contact->expires); - - TSK_OBJECT_SAFE_FREE(contactUri); - goto compute; - } - } - TSK_OBJECT_SAFE_FREE(contactUri); - } - } - } - - /* - * 3GPP TS 24.229 - - * - * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial - * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration - * was for 1200 seconds or less. - */ + int64_t expires = self->expires; + int64_t newdelay = expires; /* default value */ + const tsip_header_t* hdr; + tsk_size_t i; + + /*== NOTIFY with subscription-state header with expires parameter. + */ + if(TSIP_REQUEST_IS_NOTIFY(message)) { + const tsip_header_Subscription_State_t *hdr_state; + if((hdr_state = (const tsip_header_Subscription_State_t*)tsip_message_get_header(message, tsip_htype_Subscription_State))) { + if(hdr_state->expires >0) { + expires = TSK_TIME_S_2_MS(hdr_state->expires); + goto compute; + } + } + } + + /*== Expires header. + */ + if((hdr = tsip_message_get_header(message, tsip_htype_Expires))) { + expires = TSK_TIME_S_2_MS(((const tsip_header_Expires_t*)hdr)->delta_seconds); + goto compute; + } + + /*== Contact header. + */ + for(i=0; (hdr = tsip_message_get_headerAt(message, tsip_htype_Contact, i)); i++) { + const tsip_header_Contact_t* contact = (const tsip_header_Contact_t*)hdr; + if(contact && contact->uri) { + const char* transport = tsk_params_get_param_value(contact->uri->params, "transport"); + tsip_uri_t* contactUri = tsip_stack_get_contacturi(TSIP_DIALOG_GET_STACK(self), transport ? transport : "udp"); + if(contactUri) { + if(tsk_strequals(contact->uri->user_name, contactUri->user_name) + && tsk_strequals(contact->uri->host, contactUri->host) + && contact->uri->port == contactUri->port) { + if(contact->expires>=0) { /* No expires parameter ==> -1*/ + expires = TSK_TIME_S_2_MS(contact->expires); + + TSK_OBJECT_SAFE_FREE(contactUri); + goto compute; + } + } + TSK_OBJECT_SAFE_FREE(contactUri); + } + } + } + + /* + * 3GPP TS 24.229 - + * + * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial + * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration + * was for 1200 seconds or less. + */ compute: - expires = TSK_TIME_MS_2_S(expires); - newdelay = (expires > 1200) ? (expires - 600) : (expires/2); + expires = TSK_TIME_MS_2_S(expires); + newdelay = (expires > 1200) ? (expires - 600) : (expires/2); - return TSK_TIME_S_2_MS(newdelay); + return TSK_TIME_S_2_MS(newdelay); } /** @@ -690,488 +684,482 @@ compute: * - ... * * @param [in,out] self The calling dialog. - * @param [in,out] response The SIP/IMS response from which to get the new information. + * @param [in,out] response The SIP/IMS response from which to get the new information. * - * @return Zero if succeed and no-zero error code otherwise. + * @return Zero if succeed and no-zero error code otherwise. **/ int tsip_dialog_update(tsip_dialog_t *self, const tsip_response_t* response) { - if(self && TSIP_MESSAGE_IS_RESPONSE(response) && response->To){ - short code = TSIP_RESPONSE_CODE(response); - const char *tag = response->To->tag; - - /* - * 1xx (!100) or 2xx - */ - /* - * 401 or 407 or 421 or 494 - */ - if(code == 401 || code == 407 || code == 421 || code == 494) - { - tsk_bool_t acceptNewVector; - - /* 3GPP IMS - Each authentication vector is used only once. - * ==> Re-registration/De-registration ==> Allow 401/407 challenge. - */ - acceptNewVector = (TSIP_RESPONSE_IS_TO_REGISTER(response) && self->state == tsip_established); - return tsip_dialog_update_challenges(self, response, acceptNewVector); - } - else if(100 < code && code < 300) - { - tsip_dialog_state_t state = self->state; - - /* 1xx */ - if(code <= 199){ - if(tsk_strnullORempty(response->To->tag)){ - TSK_DEBUG_WARN("Invalid tag parameter"); - return 0; - } - state = tsip_early; - } - /* 2xx */ - else{ - state = tsip_established; - } - - /* Remote target */ - { - /* RFC 3261 12.2.1.2 Processing the Responses - When a UAC receives a 2xx response to a target refresh request, it - MUST replace the dialog's remote target URI with the URI from the - Contact header field in that response, if present. - - FIXME: Because PRACK/UPDATE sent before the session is established MUST have - the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected - */ - if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && response->Contact && response->Contact->uri){ - TSK_OBJECT_SAFE_FREE(self->uri_remote_target); - self->uri_remote_target = tsip_uri_clone(response->Contact->uri, tsk_true, tsk_false); - } - } - - /* Route sets */ - { - tsk_size_t index; - const tsip_header_Record_Route_t *recordRoute; - tsip_header_Record_Route_t *route; - - TSK_OBJECT_SAFE_FREE(self->record_routes); - - for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(response, tsip_htype_Record_Route, index)); index++){ - if(!self->record_routes){ - self->record_routes = tsk_list_create(); - } - if((route = tsk_object_ref((void*)recordRoute))){ - tsk_list_push_front_data(self->record_routes, (void**)&route); /* Copy reversed. */ - } - } - } - - - /* cseq + tags + ... */ - if(self->state == tsip_established && tsk_striequals(self->tag_remote, tag)){ - return 0; - } - else{ - if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && !TSIP_RESPONSE_IS_TO_PUBLISH(response)){ /* REGISTER and PUBLISH don't establish dialog */ - tsk_strupdate(&self->tag_remote, tag); - } + if(self && TSIP_MESSAGE_IS_RESPONSE(response) && response->To) { + short code = TSIP_RESPONSE_CODE(response); + const char *tag = response->To->tag; + + /* + * 1xx (!100) or 2xx + */ + /* + * 401 or 407 or 421 or 494 + */ + if(code == 401 || code == 407 || code == 421 || code == 494) { + tsk_bool_t acceptNewVector; + + /* 3GPP IMS - Each authentication vector is used only once. + * ==> Re-registration/De-registration ==> Allow 401/407 challenge. + */ + acceptNewVector = (TSIP_RESPONSE_IS_TO_REGISTER(response) && self->state == tsip_established); + return tsip_dialog_update_challenges(self, response, acceptNewVector); + } + else if(100 < code && code < 300) { + tsip_dialog_state_t state = self->state; + + /* 1xx */ + if(code <= 199) { + if(tsk_strnullORempty(response->To->tag)) { + TSK_DEBUG_WARN("Invalid tag parameter"); + return 0; + } + state = tsip_early; + } + /* 2xx */ + else { + state = tsip_established; + } + + /* Remote target */ + { + /* RFC 3261 12.2.1.2 Processing the Responses + When a UAC receives a 2xx response to a target refresh request, it + MUST replace the dialog's remote target URI with the URI from the + Contact header field in that response, if present. + + FIXME: Because PRACK/UPDATE sent before the session is established MUST have + the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected + */ + if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && response->Contact && response->Contact->uri) { + TSK_OBJECT_SAFE_FREE(self->uri_remote_target); + self->uri_remote_target = tsip_uri_clone(response->Contact->uri, tsk_true, tsk_false); + } + } + + /* Route sets */ + { + tsk_size_t index; + const tsip_header_Record_Route_t *recordRoute; + tsip_header_Record_Route_t *route; + + TSK_OBJECT_SAFE_FREE(self->record_routes); + + for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(response, tsip_htype_Record_Route, index)); index++) { + if(!self->record_routes) { + self->record_routes = tsk_list_create(); + } + if((route = tsk_object_ref((void*)recordRoute))) { + tsk_list_push_front_data(self->record_routes, (void**)&route); /* Copy reversed. */ + } + } + } + + + /* cseq + tags + ... */ + if(self->state == tsip_established && tsk_striequals(self->tag_remote, tag)) { + return 0; + } + else { + if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && !TSIP_RESPONSE_IS_TO_PUBLISH(response)) { /* REGISTER and PUBLISH don't establish dialog */ + tsk_strupdate(&self->tag_remote, tag); + } #if 0 // PRACK and BYE will have same CSeq value ==> Let CSeq value to be incremented by "tsip_dialog_request_new()" - self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value; + self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value; #endif - } + } - self->state = state; - return 0; - } - } - return 0; + self->state = state; + return 0; + } + } + return 0; } int tsip_dialog_update_2(tsip_dialog_t *self, const tsip_request_t* invite) { - if(!self || !invite){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* Remote target */ - if(invite->Contact && invite->Contact->uri){ - TSK_OBJECT_SAFE_FREE(self->uri_remote_target); - self->uri_remote_target = tsip_uri_clone(invite->Contact->uri, tsk_true, tsk_false); - } - - /* cseq + tags + remote-uri */ - tsk_strupdate(&self->tag_remote, invite->From?invite->From->tag:"doubango"); - /* self->cseq_value = invite->CSeq ? invite->CSeq->seq : self->cseq_value; */ - if(invite->From && invite->From->uri){ - TSK_OBJECT_SAFE_FREE(self->uri_remote); - self->uri_remote = tsk_object_ref(invite->From->uri); - } - - /* Route sets */ - { - tsk_size_t index; - const tsip_header_Record_Route_t *recordRoute; - tsip_header_Record_Route_t* route; - - TSK_OBJECT_SAFE_FREE(self->record_routes); - - for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(invite, tsip_htype_Record_Route, index)); index++){ - if(!self->record_routes){ - self->record_routes = tsk_list_create(); - } - if((route = tsk_object_ref((void*)recordRoute))){ - tsk_list_push_back_data(self->record_routes, (void**)&route); /* Copy non-reversed. */ - } - } - } - - self->state = tsip_established; - - return 0; + if(!self || !invite) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + /* Remote target */ + if(invite->Contact && invite->Contact->uri) { + TSK_OBJECT_SAFE_FREE(self->uri_remote_target); + self->uri_remote_target = tsip_uri_clone(invite->Contact->uri, tsk_true, tsk_false); + } + + /* cseq + tags + remote-uri */ + tsk_strupdate(&self->tag_remote, invite->From?invite->From->tag:"doubango"); + /* self->cseq_value = invite->CSeq ? invite->CSeq->seq : self->cseq_value; */ + if(invite->From && invite->From->uri) { + TSK_OBJECT_SAFE_FREE(self->uri_remote); + self->uri_remote = tsk_object_ref(invite->From->uri); + } + + /* Route sets */ + { + tsk_size_t index; + const tsip_header_Record_Route_t *recordRoute; + tsip_header_Record_Route_t* route; + + TSK_OBJECT_SAFE_FREE(self->record_routes); + + for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(invite, tsip_htype_Record_Route, index)); index++) { + if(!self->record_routes) { + self->record_routes = tsk_list_create(); + } + if((route = tsk_object_ref((void*)recordRoute))) { + tsk_list_push_back_data(self->record_routes, (void**)&route); /* Copy non-reversed. */ + } + } + } + + self->state = tsip_established; + + return 0; } int tsip_dialog_getCKIK(tsip_dialog_t *self, AKA_CK_T *ck, AKA_IK_T *ik) { - tsk_list_item_t *item; - tsip_challenge_t *challenge; - - if(!self){ - return -1; - } - - tsk_list_foreach(item, self->challenges) - { - if((challenge = item->data)){ - memcpy(*ck, challenge->ck, AKA_CK_SIZE); - memcpy(*ik, challenge->ik, AKA_IK_SIZE); - return 0; - } - } - TSK_DEBUG_ERROR("No challenge found. Fail to set IK and CK."); - return -2; + tsk_list_item_t *item; + tsip_challenge_t *challenge; + + if(!self) { + return -1; + } + + tsk_list_foreach(item, self->challenges) { + if((challenge = item->data)) { + memcpy(*ck, challenge->ck, AKA_CK_SIZE); + memcpy(*ik, challenge->ik, AKA_IK_SIZE); + return 0; + } + } + TSK_DEBUG_ERROR("No challenge found. Fail to set IK and CK."); + return -2; } int tsip_dialog_update_challenges(tsip_dialog_t *self, const tsip_response_t* response, int acceptNewVector) { - int ret = -1; - tsk_size_t i; - - tsk_list_item_t *item; - - tsip_challenge_t *challenge; - - const tsip_header_WWW_Authenticate_t *WWW_Authenticate; - const tsip_header_Proxy_Authenticate_t *Proxy_Authenticate; - - /* RFC 2617 - HTTP Digest Session - - * (A) The client response to a WWW-Authenticate challenge for a protection - space starts an authentication session with that protection space. - The authentication session lasts until the client receives another - WWW-Authenticate challenge from any server in the protection space. - - (B) The server may return a 401 response with a new nonce value, causing the client - to retry the request; by specifying stale=TRUE with this response, - the server tells the client to retry with the new nonce, but without - prompting for a new username and password. - */ - /* RFC 2617 - 1.2 Access Authentication Framework - The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge. - */ - - /* FIXME: As we perform the same task ==> Use only one loop. - */ - - for(i =0; (WWW_Authenticate = (const tsip_header_WWW_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_WWW_Authenticate, i)); i++){ - tsk_bool_t isnew = tsk_true; - - tsk_list_foreach(item, self->challenges){ - challenge = item->data; - if(challenge->isproxy) continue; - - if(tsk_striequals(challenge->realm, WWW_Authenticate->realm) && (WWW_Authenticate->stale || acceptNewVector)){ - /*== (B) ==*/ - if((ret = tsip_challenge_update(challenge, - WWW_Authenticate->scheme, - WWW_Authenticate->realm, - WWW_Authenticate->nonce, - WWW_Authenticate->opaque, - WWW_Authenticate->algorithm, - WWW_Authenticate->qop))) - { - return ret; - } - else{ - isnew = tsk_false; - continue; - } - } - else{ - TSK_DEBUG_ERROR("Failed to handle new challenge"); - return -1; - } - } - - if(isnew){ - if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self), - tsk_false, - WWW_Authenticate->scheme, - WWW_Authenticate->realm, - WWW_Authenticate->nonce, - WWW_Authenticate->opaque, - WWW_Authenticate->algorithm, - WWW_Authenticate->qop))) - { - if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi){ - tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1); - } - tsk_list_push_back_data(self->challenges, (void**)&challenge); - } - else{ - TSK_DEBUG_ERROR("Failed to handle new challenge"); - return -1; - } - } - } - - for(i=0; (Proxy_Authenticate = (const tsip_header_Proxy_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_Proxy_Authenticate, i)); i++){ - tsk_bool_t isnew = tsk_true; - - tsk_list_foreach(item, self->challenges){ - challenge = item->data; - if(!challenge->isproxy){ - continue; - } - - if(tsk_striequals(challenge->realm, Proxy_Authenticate->realm) && (Proxy_Authenticate->stale || acceptNewVector)){ - /*== (B) ==*/ - if((ret = tsip_challenge_update(challenge, - Proxy_Authenticate->scheme, - Proxy_Authenticate->realm, - Proxy_Authenticate->nonce, - Proxy_Authenticate->opaque, - Proxy_Authenticate->algorithm, - Proxy_Authenticate->qop))) - { - return ret; - } - else{ - isnew = tsk_false; - continue; - } - } - else{ - TSK_DEBUG_ERROR("Failed to handle new challenge"); - return -1; - } - } - - if(isnew){ - if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self), - tsk_true, - Proxy_Authenticate->scheme, - Proxy_Authenticate->realm, - Proxy_Authenticate->nonce, - Proxy_Authenticate->opaque, - Proxy_Authenticate->algorithm, - Proxy_Authenticate->qop))) - { - if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi){ - tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1); - } - tsk_list_push_back_data(self->challenges, (void**)&challenge); - } - else{ - TSK_DEBUG_ERROR("Failed to handle new challenge"); - return -1; - } - } - } - return 0; + int ret = -1; + tsk_size_t i; + + tsk_list_item_t *item; + + tsip_challenge_t *challenge; + + const tsip_header_WWW_Authenticate_t *WWW_Authenticate; + const tsip_header_Proxy_Authenticate_t *Proxy_Authenticate; + + /* RFC 2617 - HTTP Digest Session + + * (A) The client response to a WWW-Authenticate challenge for a protection + space starts an authentication session with that protection space. + The authentication session lasts until the client receives another + WWW-Authenticate challenge from any server in the protection space. + + (B) The server may return a 401 response with a new nonce value, causing the client + to retry the request; by specifying stale=TRUE with this response, + the server tells the client to retry with the new nonce, but without + prompting for a new username and password. + */ + /* RFC 2617 - 1.2 Access Authentication Framework + The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge. + */ + + /* FIXME: As we perform the same task ==> Use only one loop. + */ + + for(i =0; (WWW_Authenticate = (const tsip_header_WWW_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_WWW_Authenticate, i)); i++) { + tsk_bool_t isnew = tsk_true; + + tsk_list_foreach(item, self->challenges) { + challenge = item->data; + if(challenge->isproxy) { + continue; + } + + if(tsk_striequals(challenge->realm, WWW_Authenticate->realm) && (WWW_Authenticate->stale || acceptNewVector)) { + /*== (B) ==*/ + if((ret = tsip_challenge_update(challenge, + WWW_Authenticate->scheme, + WWW_Authenticate->realm, + WWW_Authenticate->nonce, + WWW_Authenticate->opaque, + WWW_Authenticate->algorithm, + WWW_Authenticate->qop))) { + return ret; + } + else { + isnew = tsk_false; + continue; + } + } + else { + TSK_DEBUG_ERROR("Failed to handle new challenge"); + return -1; + } + } + + if(isnew) { + if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self), + tsk_false, + WWW_Authenticate->scheme, + WWW_Authenticate->realm, + WWW_Authenticate->nonce, + WWW_Authenticate->opaque, + WWW_Authenticate->algorithm, + WWW_Authenticate->qop))) { + if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi) { + tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1); + } + tsk_list_push_back_data(self->challenges, (void**)&challenge); + } + else { + TSK_DEBUG_ERROR("Failed to handle new challenge"); + return -1; + } + } + } + + for(i=0; (Proxy_Authenticate = (const tsip_header_Proxy_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_Proxy_Authenticate, i)); i++) { + tsk_bool_t isnew = tsk_true; + + tsk_list_foreach(item, self->challenges) { + challenge = item->data; + if(!challenge->isproxy) { + continue; + } + + if(tsk_striequals(challenge->realm, Proxy_Authenticate->realm) && (Proxy_Authenticate->stale || acceptNewVector)) { + /*== (B) ==*/ + if((ret = tsip_challenge_update(challenge, + Proxy_Authenticate->scheme, + Proxy_Authenticate->realm, + Proxy_Authenticate->nonce, + Proxy_Authenticate->opaque, + Proxy_Authenticate->algorithm, + Proxy_Authenticate->qop))) { + return ret; + } + else { + isnew = tsk_false; + continue; + } + } + else { + TSK_DEBUG_ERROR("Failed to handle new challenge"); + return -1; + } + } + + if(isnew) { + if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self), + tsk_true, + Proxy_Authenticate->scheme, + Proxy_Authenticate->realm, + Proxy_Authenticate->nonce, + Proxy_Authenticate->opaque, + Proxy_Authenticate->algorithm, + Proxy_Authenticate->qop))) { + if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi) { + tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1); + } + tsk_list_push_back_data(self->challenges, (void**)&challenge); + } + else { + TSK_DEBUG_ERROR("Failed to handle new challenge"); + return -1; + } + } + } + return 0; } int tsip_dialog_add_session_headers(const tsip_dialog_t *self, tsip_request_t* request) { - if(!self || !request){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self || !request) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - TSIP_DIALOG_ADD_HEADERS(self->ss->headers); - return 0; + TSIP_DIALOG_ADD_HEADERS(self->ss->headers); + return 0; } int tsip_dialog_add_common_headers(const tsip_dialog_t *self, tsip_request_t* request) { - tsk_bool_t earlyIMS = tsk_false; - const tsip_uri_t* preferred_identity = tsk_null; - const char* netinfo = tsk_null; - - if(!self || !request){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - earlyIMS = TSIP_DIALOG_GET_STACK(self)->security.earlyIMS; - preferred_identity = TSIP_DIALOG_GET_STACK(self)->identity.preferred; - - // - // P-Preferred-Identity - // - if(preferred_identity && TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))){ - /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE - The UE shall use the temporary public user identity (IMSI-derived IMPU, cf. section 6.1.2) only in registration - messages (i.e. initial registration, re-registration or de-registration), but not in any other type of SIP requests. - */ - switch(request->line.request.request_type){ - case tsip_BYE: - case tsip_INVITE: - case tsip_OPTIONS: - case tsip_SUBSCRIBE: - case tsip_NOTIFY: - case tsip_REFER: - case tsip_MESSAGE: - case tsip_PUBLISH: - case tsip_REGISTER: - { - if(!earlyIMS || (earlyIMS && TSIP_REQUEST_IS_REGISTER(request))){ - TSIP_MESSAGE_ADD_HEADER(request, - TSIP_HEADER_P_PREFERRED_IDENTITY_VA_ARGS(preferred_identity) - ); - } - break; - } - default:break; - } - } - - // - // P-Access-Network-Info - // - if(netinfo) - { - switch(request->line.request.request_type){ - case tsip_BYE: - case tsip_INVITE: - case tsip_OPTIONS: - case tsip_REGISTER: - case tsip_SUBSCRIBE: - case tsip_NOTIFY: - case tsip_PRACK: - case tsip_INFO: - case tsip_UPDATE: - case tsip_REFER: - case tsip_MESSAGE: - case tsip_PUBLISH: - { - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_P_ACCESS_NETWORK_INFO_VA_ARGS(netinfo)); - break; - } - default: break; - } - } - - return 0; + tsk_bool_t earlyIMS = tsk_false; + const tsip_uri_t* preferred_identity = tsk_null; + const char* netinfo = tsk_null; + + if(!self || !request) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + earlyIMS = TSIP_DIALOG_GET_STACK(self)->security.earlyIMS; + preferred_identity = TSIP_DIALOG_GET_STACK(self)->identity.preferred; + + // + // P-Preferred-Identity + // + if(preferred_identity && TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))) { + /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE + The UE shall use the temporary public user identity (IMSI-derived IMPU, cf. section 6.1.2) only in registration + messages (i.e. initial registration, re-registration or de-registration), but not in any other type of SIP requests. + */ + switch(request->line.request.request_type) { + case tsip_BYE: + case tsip_INVITE: + case tsip_OPTIONS: + case tsip_SUBSCRIBE: + case tsip_NOTIFY: + case tsip_REFER: + case tsip_MESSAGE: + case tsip_PUBLISH: + case tsip_REGISTER: { + if(!earlyIMS || (earlyIMS && TSIP_REQUEST_IS_REGISTER(request))) { + TSIP_MESSAGE_ADD_HEADER(request, + TSIP_HEADER_P_PREFERRED_IDENTITY_VA_ARGS(preferred_identity) + ); + } + break; + } + default: + break; + } + } + + // + // P-Access-Network-Info + // + if(netinfo) { + switch(request->line.request.request_type) { + case tsip_BYE: + case tsip_INVITE: + case tsip_OPTIONS: + case tsip_REGISTER: + case tsip_SUBSCRIBE: + case tsip_NOTIFY: + case tsip_PRACK: + case tsip_INFO: + case tsip_UPDATE: + case tsip_REFER: + case tsip_MESSAGE: + case tsip_PUBLISH: { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_P_ACCESS_NETWORK_INFO_VA_ARGS(netinfo)); + break; + } + default: + break; + } + } + + return 0; } int tsip_dialog_init(tsip_dialog_t *self, tsip_dialog_type_t type, const char* call_id, tsip_ssession_t* ss, tsk_fsm_state_id curr, tsk_fsm_state_id term) { - static tsip_dialog_id_t unique_id = 0; - if(self){ - if(self->initialized){ - TSK_DEBUG_WARN("Dialog already initialized."); - return -2; - } - - self->state = tsip_initial; - self->type = type; - self->id = ++unique_id; - self->connected_fd = TNET_INVALID_FD; - if(!self->record_routes){ - self->record_routes = tsk_list_create(); - } - if(!self->challenges){ - self->challenges = tsk_list_create(); - } - - /* Sets some defalt values */ - self->expires = TSIP_SSESSION_EXPIRES_DEFAULT; - - if(call_id){ - /* "server-side" session */ - tsk_strupdate(&self->callid, call_id); - } - else{ - tsk_uuidstring_t uuid; /* Call-id is a random UUID */ - tsip_header_Call_ID_random(&uuid); - tsk_strupdate(&self->callid, uuid); - } - - /* ref SIP session */ - self->ss = tsk_object_ref(ss); - - /* Local tag */{ - tsk_istr_t tag; - tsk_strrandom(&tag); - tsk_strupdate(&self->tag_local, tag); - } - - /* CSeq */ - self->cseq_value = (rand() + 1); - - /* FSM */ - self->fsm = tsk_fsm_create(curr, term); - - /*=== SIP Session ===*/ - if(self->ss != TSIP_SSESSION_INVALID_HANDLE){ - - /* Expires */ - self->expires = ss->expires; - - /* From */ - self->uri_local = tsk_object_ref(call_id/* "server-side" */ ? ss->to : ss->from); - - /* To */ - if(ss->to){ - self->uri_remote = tsk_object_ref(ss->to); - self->uri_remote_target = tsk_object_ref(ss->to); /* Request-URI. */ - } - else{ - self->uri_remote = tsk_object_ref(ss->from); - self->uri_remote_target = tsk_object_ref((void*)TSIP_DIALOG_GET_STACK(self)->network.realm); - } - } - else{ - TSK_DEBUG_ERROR("Invalid SIP Session id."); - } - - tsk_safeobj_init(self); - - self->initialized = tsk_true; - return 0; - } - return -1; + static tsip_dialog_id_t unique_id = 0; + if(self) { + if(self->initialized) { + TSK_DEBUG_WARN("Dialog already initialized."); + return -2; + } + + self->state = tsip_initial; + self->type = type; + self->id = ++unique_id; + self->connected_fd = TNET_INVALID_FD; + if(!self->record_routes) { + self->record_routes = tsk_list_create(); + } + if(!self->challenges) { + self->challenges = tsk_list_create(); + } + + /* Sets some defalt values */ + self->expires = TSIP_SSESSION_EXPIRES_DEFAULT; + + if(call_id) { + /* "server-side" session */ + tsk_strupdate(&self->callid, call_id); + } + else { + tsk_uuidstring_t uuid; /* Call-id is a random UUID */ + tsip_header_Call_ID_random(&uuid); + tsk_strupdate(&self->callid, uuid); + } + + /* ref SIP session */ + self->ss = tsk_object_ref(ss); + + /* Local tag */{ + tsk_istr_t tag; + tsk_strrandom(&tag); + tsk_strupdate(&self->tag_local, tag); + } + + /* CSeq */ + self->cseq_value = (rand() + 1); + + /* FSM */ + self->fsm = tsk_fsm_create(curr, term); + + /*=== SIP Session ===*/ + if(self->ss != TSIP_SSESSION_INVALID_HANDLE) { + + /* Expires */ + self->expires = ss->expires; + + /* From */ + self->uri_local = tsk_object_ref(call_id/* "server-side" */ ? ss->to : ss->from); + + /* To */ + if(ss->to) { + self->uri_remote = tsk_object_ref(ss->to); + self->uri_remote_target = tsk_object_ref(ss->to); /* Request-URI. */ + } + else { + self->uri_remote = tsk_object_ref(ss->from); + self->uri_remote_target = tsk_object_ref((void*)TSIP_DIALOG_GET_STACK(self)->network.realm); + } + } + else { + TSK_DEBUG_ERROR("Invalid SIP Session id."); + } + + tsk_safeobj_init(self); + + self->initialized = tsk_true; + return 0; + } + return -1; } int tsip_dialog_fsm_act(tsip_dialog_t* self, tsk_fsm_action_id action_id, const tsip_message_t* message, const tsip_action_handle_t* action) { - int ret; - tsip_dialog_t* copy; - if(!self || !self->fsm){ - TSK_DEBUG_ERROR("Invalid parameter."); - return -1; - } - - tsk_safeobj_lock(self); - copy = tsk_object_ref(self); /* keep a copy because tsk_fsm_act() could destroy the dialog */ - ret = tsip_dialog_set_curr_action(copy, action); - ret = tsk_fsm_act(copy->fsm, action_id, copy, message, copy, message, action); - tsk_safeobj_unlock(copy); - tsk_object_unref(copy); - - return ret; + int ret; + tsip_dialog_t* copy; + if(!self || !self->fsm) { + TSK_DEBUG_ERROR("Invalid parameter."); + return -1; + } + + tsk_safeobj_lock(self); + copy = tsk_object_ref(self); /* keep a copy because tsk_fsm_act() could destroy the dialog */ + ret = tsip_dialog_set_curr_action(copy, action); + ret = tsk_fsm_act(copy->fsm, action_id, copy, message, copy, message, action); + tsk_safeobj_unlock(copy); + tsk_object_unref(copy); + + return ret; } /* @@ -1179,176 +1167,175 @@ This function is used to know if we need to keep the same action handle after re */ tsk_bool_t tsip_dialog_keep_action(const tsip_dialog_t* self, const tsip_response_t *response) { - if(self && response){ - const short code = TSIP_RESPONSE_CODE(response); - return - TSIP_RESPONSE_IS_1XX(response) || - (code == 401 || code == 407 || code == 421 || code == 494) || - (code == 422 || code == 423); - } - return tsk_false; + if(self && response) { + const short code = TSIP_RESPONSE_CODE(response); + return + TSIP_RESPONSE_IS_1XX(response) || + (code == 401 || code == 407 || code == 421 || code == 494) || + (code == 422 || code == 423); + } + return tsk_false; } int tsip_dialog_set_connected_fd(tsip_dialog_t* self, tnet_fd_t fd) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->connected_fd = fd; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->connected_fd = fd; + return 0; } int tsip_dialog_set_curr_action(tsip_dialog_t* self, const tsip_action_t* action) { - tsip_action_t* new_action; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter."); - return -1; - } - - new_action = tsk_object_ref((void*)action); - TSK_OBJECT_SAFE_FREE(self->curr_action); - self->curr_action = new_action; - return 0; + tsip_action_t* new_action; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter."); + return -1; + } + + new_action = tsk_object_ref((void*)action); + TSK_OBJECT_SAFE_FREE(self->curr_action); + self->curr_action = new_action; + return 0; } int tsip_dialog_set_lasterror_2(tsip_dialog_t* self, const char* phrase, short code, const tsip_message_t *message) { - if(!self || tsk_strnullORempty(phrase)){ - TSK_DEBUG_ERROR("Invalid parameter."); - return -1; - } - - tsk_strupdate(&self->last_error.phrase, phrase); - self->last_error.code = code; - TSK_OBJECT_SAFE_FREE(self->last_error.message); - if(message){ - self->last_error.message = (tsip_message_t*)tsk_object_ref((void*)message); - } - return 0; + if(!self || tsk_strnullORempty(phrase)) { + TSK_DEBUG_ERROR("Invalid parameter."); + return -1; + } + + tsk_strupdate(&self->last_error.phrase, phrase); + self->last_error.code = code; + TSK_OBJECT_SAFE_FREE(self->last_error.message); + if(message) { + self->last_error.message = (tsip_message_t*)tsk_object_ref((void*)message); + } + return 0; } int tsip_dialog_set_lasterror(tsip_dialog_t* self, const char* phrase, short code) { - return tsip_dialog_set_lasterror_2(self, phrase, code, tsk_null); + return tsip_dialog_set_lasterror_2(self, phrase, code, tsk_null); } int tsip_dialog_get_lasterror(const tsip_dialog_t* self, short *code, const char** phrase, const tsip_message_t **message) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter."); - return -1; - } - - if(code){ - *code = self->last_error.code; - } - if(phrase){ - *phrase = self->last_error.phrase; - } - - if(message){ - *message = self->last_error.message; - } - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter."); + return -1; + } + + if(code) { + *code = self->last_error.code; + } + if(phrase) { + *phrase = self->last_error.phrase; + } + + if(message) { + *message = self->last_error.message; + } + + return 0; } int tsip_dialog_hangup(tsip_dialog_t *self, const tsip_action_t* action) { - if(self){ - // CANCEL should only be sent for INVITE dialog - if(self->type != tsip_dialog_INVITE || self->state == tsip_established){ - return tsip_dialog_fsm_act(self, tsip_atype_hangup, tsk_null, action); - } - else{ - return tsip_dialog_fsm_act(self, tsip_atype_cancel, tsk_null, action); - } - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self) { + // CANCEL should only be sent for INVITE dialog + if(self->type != tsip_dialog_INVITE || self->state == tsip_established) { + return tsip_dialog_fsm_act(self, tsip_atype_hangup, tsk_null, action); + } + else { + return tsip_dialog_fsm_act(self, tsip_atype_cancel, tsk_null, action); + } + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } int tsip_dialog_shutdown(tsip_dialog_t *self, const tsip_action_t* action) { - if(self){ - return tsip_dialog_fsm_act(self, tsip_atype_shutdown, tsk_null, action); - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self) { + return tsip_dialog_fsm_act(self, tsip_atype_shutdown, tsk_null, action); + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } int tsip_dialog_signal_transport_error(tsip_dialog_t *self) { - if(self){ - return tsip_dialog_fsm_act(self, tsip_atype_transport_error, tsk_null, tsk_null); - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self) { + return tsip_dialog_fsm_act(self, tsip_atype_transport_error, tsk_null, tsk_null); + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } int tsip_dialog_remove(const tsip_dialog_t* self) { - return tsip_dialog_layer_remove(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG(self)); + return tsip_dialog_layer_remove(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG(self)); } int tsip_dialog_cmp(const tsip_dialog_t *d1, const tsip_dialog_t *d2) { - if(d1 && d2){ - if( - tsk_strequals(d1->callid, d2->callid) - && (tsk_strequals(d1->tag_local, d2->tag_local)) - && (tsk_strequals(d1->tag_remote, d2->tag_remote)) - ) - { - return 0; - } - } - return -1; + if(d1 && d2) { + if( + tsk_strequals(d1->callid, d2->callid) + && (tsk_strequals(d1->tag_local, d2->tag_local)) + && (tsk_strequals(d1->tag_remote, d2->tag_remote)) + ) { + return 0; + } + } + return -1; } int tsip_dialog_deinit(tsip_dialog_t *self) { - if(self){ - if(!self->initialized){ - TSK_DEBUG_WARN("Dialog not initialized."); - return -2; - } - - /* Cancel all transactions associated to this dialog (do it here before the dialog becomes unsafe) */ - tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, self); - - /* Remove the dialog from the Stream peers */ - tsip_dialog_layer_remove_callid_from_stream_peers(TSIP_DIALOG_GET_STACK(self)->layer_dialog, self->callid); - - TSK_OBJECT_SAFE_FREE(self->ss); - TSK_OBJECT_SAFE_FREE(self->curr_action); - - TSK_OBJECT_SAFE_FREE(self->uri_local); - TSK_FREE(self->tag_local); - TSK_OBJECT_SAFE_FREE(self->uri_remote); - TSK_FREE(self->tag_remote); - - TSK_OBJECT_SAFE_FREE(self->uri_remote_target); - - TSK_FREE(self->cseq_method); - TSK_FREE(self->callid); - - TSK_FREE(self->last_error.phrase); - TSK_OBJECT_SAFE_FREE(self->last_error.message); - - TSK_OBJECT_SAFE_FREE(self->record_routes); - TSK_OBJECT_SAFE_FREE(self->challenges); - - TSK_OBJECT_SAFE_FREE(self->fsm); - - tsk_safeobj_deinit(self); - - self->initialized = 0; - - return 0; - } - return -1; + if(self) { + if(!self->initialized) { + TSK_DEBUG_WARN("Dialog not initialized."); + return -2; + } + + /* Cancel all transactions associated to this dialog (do it here before the dialog becomes unsafe) */ + tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, self); + + /* Remove the dialog from the Stream peers */ + tsip_dialog_layer_remove_callid_from_stream_peers(TSIP_DIALOG_GET_STACK(self)->layer_dialog, self->callid); + + TSK_OBJECT_SAFE_FREE(self->ss); + TSK_OBJECT_SAFE_FREE(self->curr_action); + + TSK_OBJECT_SAFE_FREE(self->uri_local); + TSK_FREE(self->tag_local); + TSK_OBJECT_SAFE_FREE(self->uri_remote); + TSK_FREE(self->tag_remote); + + TSK_OBJECT_SAFE_FREE(self->uri_remote_target); + + TSK_FREE(self->cseq_method); + TSK_FREE(self->callid); + + TSK_FREE(self->last_error.phrase); + TSK_OBJECT_SAFE_FREE(self->last_error.message); + + TSK_OBJECT_SAFE_FREE(self->record_routes); + TSK_OBJECT_SAFE_FREE(self->challenges); + + TSK_OBJECT_SAFE_FREE(self->fsm); + + tsk_safeobj_deinit(self); + + self->initialized = 0; + + return 0; + } + return -1; } diff --git a/tinySIP/src/dialogs/tsip_dialog_info.c b/tinySIP/src/dialogs/tsip_dialog_info.c index 0ff2536..aa8bc6d 100755 --- a/tinySIP/src/dialogs/tsip_dialog_info.c +++ b/tinySIP/src/dialogs/tsip_dialog_info.c @@ -2,19 +2,19 @@ * Copyright (C) 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. * @@ -65,156 +65,149 @@ static int tsip_dialog_info_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ /* ======================== actions ======================== */ -typedef enum _fsm_action_e -{ - _fsm_action_sendINFO = tsip_atype_info_send, - _fsm_action_accept = tsip_atype_accept, - _fsm_action_reject = tsip_atype_reject, - _fsm_action_cancel = tsip_atype_cancel, - _fsm_action_shutdown = tsip_atype_shutdown, - _fsm_action_transporterror = tsip_atype_transport_error, - - _fsm_action_receiveINFO = 0xFF, - _fsm_action_1xx, - _fsm_action_2xx, - _fsm_action_401_407_421_494, - _fsm_action_300_to_699, - _fsm_action_error, +typedef enum _fsm_action_e { + _fsm_action_sendINFO = tsip_atype_info_send, + _fsm_action_accept = tsip_atype_accept, + _fsm_action_reject = tsip_atype_reject, + _fsm_action_cancel = tsip_atype_cancel, + _fsm_action_shutdown = tsip_atype_shutdown, + _fsm_action_transporterror = tsip_atype_transport_error, + + _fsm_action_receiveINFO = 0xFF, + _fsm_action_1xx, + _fsm_action_2xx, + _fsm_action_401_407_421_494, + _fsm_action_300_to_699, + _fsm_action_error, } _fsm_action_t; /* ======================== states ======================== */ -typedef enum _fsm_state_e -{ - _fsm_state_Started, - _fsm_state_Sending, - _fsm_state_Receiving, - _fsm_state_Terminated +typedef enum _fsm_state_e { + _fsm_state_Started, + _fsm_state_Sending, + _fsm_state_Receiving, + _fsm_state_Terminated } _fsm_state_t; static int tsip_dialog_info_event_callback(const tsip_dialog_info_t *self, tsip_dialog_event_type_t type, const tsip_message_t *msg) { - int ret = -1; - - switch(type) - { - case tsip_dialog_i_msg: - { - if(msg) - { - if(TSIP_MESSAGE_IS_RESPONSE(msg)) - { - if(TSIP_RESPONSE_IS_1XX(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, tsk_null); - } - else if(TSIP_RESPONSE_IS_2XX(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, tsk_null); - } - else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407 || TSIP_RESPONSE_CODE(msg) == 421 || TSIP_RESPONSE_CODE(msg) == 494){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, tsk_null); - } - else if(TSIP_RESPONSE_IS_3456(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_300_to_699, msg, tsk_null); - } - else{ /* Should never happen */ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, tsk_null); - } - } - else if (TSIP_REQUEST_IS_INFO(msg)){ /* have been checked by dialog layer...but */ - // REQUEST ==> Incoming INFO - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveINFO, msg, tsk_null); - } - } - break; - } - - case tsip_dialog_canceled: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); - break; - } - - case tsip_dialog_terminated: - case tsip_dialog_timedout: - case tsip_dialog_error: - case tsip_dialog_transport_error: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); - break; - } - - default: break; - } - - return ret; + int ret = -1; + + switch(type) { + case tsip_dialog_i_msg: { + if(msg) { + if(TSIP_MESSAGE_IS_RESPONSE(msg)) { + if(TSIP_RESPONSE_IS_1XX(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, tsk_null); + } + else if(TSIP_RESPONSE_IS_2XX(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, tsk_null); + } + else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407 || TSIP_RESPONSE_CODE(msg) == 421 || TSIP_RESPONSE_CODE(msg) == 494) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, tsk_null); + } + else if(TSIP_RESPONSE_IS_3456(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_300_to_699, msg, tsk_null); + } + else { /* Should never happen */ + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, tsk_null); + } + } + else if (TSIP_REQUEST_IS_INFO(msg)) { /* have been checked by dialog layer...but */ + // REQUEST ==> Incoming INFO + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveINFO, msg, tsk_null); + } + } + break; + } + + case tsip_dialog_canceled: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); + break; + } + + case tsip_dialog_terminated: + case tsip_dialog_timedout: + case tsip_dialog_error: + case tsip_dialog_transport_error: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); + break; + } + + default: + break; + } + + return ret; } tsip_dialog_info_t* tsip_dialog_info_create(const tsip_ssession_handle_t* ss) { - return tsk_object_new(tsip_dialog_info_def_t, ss); + return tsk_object_new(tsip_dialog_info_def_t, ss); } int tsip_dialog_info_init(tsip_dialog_info_t *self) { - //const tsk_param_t* param; - - /* Initialize the state machine. */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (send) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_sendINFO, _fsm_state_Sending, tsip_dialog_info_Started_2_Sending_X_sendINFO, "tsip_dialog_info_Started_2_Sending_X_sendINFO"), - // Started -> (receive) -> Receiving - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveINFO, _fsm_state_Receiving, tsip_dialog_info_Started_2_Receiving_X_recvINFO, "tsip_dialog_info_Started_2_Receiving_X_recvINFO"), - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_info_Started_2_Started_X_any"), - - - /*======================= - * === Sending === - */ - // Sending -> (1xx) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_info_Sending_2_Sending_X_1xx, "tsip_dialog_info_Sending_2_Sending_X_1xx"), - // Sending -> (2xx) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_2xx, "tsip_dialog_info_Sending_2_Terminated_X_2xx"), - // Sending -> (401/407/421/494) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_401_407_421_494, _fsm_state_Sending, tsip_dialog_info_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_info_Sending_2_Sending_X_401_407_421_494"), - // Sending -> (300_to_699) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_300_to_699, "tsip_dialog_info_Sending_2_Terminated_X_300_to_699"), - // Sending -> (cancel) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_cancel, "tsip_dialog_info_Sending_2_Terminated_X_cancel"), - // Sending -> (shutdown) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_info_Sending_2_Terminated_X_shutdown"), - // Sending -> (Any) -> Sending - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_info_Sending_2_Sending_X_any"), - - /*======================= - * === Receiving === - */ - // Receiving -> (accept) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_info_Receiving_2_Terminated_X_accept, "tsip_dialog_info_Receiving_2_Terminated_X_accept"), - // Receiving -> (rejected) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_info_Receiving_2_Terminated_X_reject, "tsip_dialog_info_Receiving_2_Terminated_X_reject"), - // Receiving -> (Any) -> Receiving - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_info_Receiving_2_Receiving_X_any"), - - /*======================= - * === Any === - */ - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_info_Any_2_Terminated_X_transportError, "tsip_dialog_info_Any_2_Terminated_X_transportError"), - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_info_Any_2_Terminated_X_Error, "tsip_dialog_info_Any_2_Terminated_X_Error"), - - TSK_FSM_ADD_NULL()); - - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_info_event_callback); - - return 0; + //const tsk_param_t* param; + + /* Initialize the state machine. */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (send) -> Sending + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_sendINFO, _fsm_state_Sending, tsip_dialog_info_Started_2_Sending_X_sendINFO, "tsip_dialog_info_Started_2_Sending_X_sendINFO"), + // Started -> (receive) -> Receiving + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveINFO, _fsm_state_Receiving, tsip_dialog_info_Started_2_Receiving_X_recvINFO, "tsip_dialog_info_Started_2_Receiving_X_recvINFO"), + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_info_Started_2_Started_X_any"), + + + /*======================= + * === Sending === + */ + // Sending -> (1xx) -> Sending + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_info_Sending_2_Sending_X_1xx, "tsip_dialog_info_Sending_2_Sending_X_1xx"), + // Sending -> (2xx) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_2xx, "tsip_dialog_info_Sending_2_Terminated_X_2xx"), + // Sending -> (401/407/421/494) -> Sending + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_401_407_421_494, _fsm_state_Sending, tsip_dialog_info_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_info_Sending_2_Sending_X_401_407_421_494"), + // Sending -> (300_to_699) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_300_to_699, "tsip_dialog_info_Sending_2_Terminated_X_300_to_699"), + // Sending -> (cancel) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_info_Sending_2_Terminated_X_cancel, "tsip_dialog_info_Sending_2_Terminated_X_cancel"), + // Sending -> (shutdown) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_info_Sending_2_Terminated_X_shutdown"), + // Sending -> (Any) -> Sending + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_info_Sending_2_Sending_X_any"), + + /*======================= + * === Receiving === + */ + // Receiving -> (accept) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_info_Receiving_2_Terminated_X_accept, "tsip_dialog_info_Receiving_2_Terminated_X_accept"), + // Receiving -> (rejected) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_info_Receiving_2_Terminated_X_reject, "tsip_dialog_info_Receiving_2_Terminated_X_reject"), + // Receiving -> (Any) -> Receiving + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_info_Receiving_2_Receiving_X_any"), + + /*======================= + * === Any === + */ + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_info_Any_2_Terminated_X_transportError, "tsip_dialog_info_Any_2_Terminated_X_transportError"), + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_info_Any_2_Terminated_X_Error, "tsip_dialog_info_Any_2_Terminated_X_Error"), + + TSK_FSM_ADD_NULL()); + + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_info_event_callback); + + return 0; } @@ -227,219 +220,219 @@ int tsip_dialog_info_init(tsip_dialog_info_t *self) */ int tsip_dialog_info_Started_2_Sending_X_sendINFO(va_list *app) { - tsip_dialog_info_t *self; - const tsip_action_t* action; + tsip_dialog_info_t *self; + const tsip_action_t* action; - self = va_arg(*app, tsip_dialog_info_t *); - va_arg(*app, tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); + self = va_arg(*app, tsip_dialog_info_t *); + va_arg(*app, tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - return send_INFO(self); + return send_INFO(self); } /* Started -> (recvINFO) -> Receiving */ int tsip_dialog_info_Started_2_Receiving_X_recvINFO(va_list *app) { - tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - - /* Alert the user. */ - TSIP_DIALOG_INFO_SIGNAL(self, tsip_i_info, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - - /* Update last incoming INFO */ - TSK_OBJECT_SAFE_FREE(self->last_iMessage); - self->last_iMessage = tsk_object_ref((void*)request); - - return 0; + tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + + /* Alert the user. */ + TSIP_DIALOG_INFO_SIGNAL(self, tsip_i_info, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + + /* Update last incoming INFO */ + TSK_OBJECT_SAFE_FREE(self->last_iMessage); + self->last_iMessage = tsk_object_ref((void*)request); + + return 0; } /* Sending -> (1xx) -> Sending */ int tsip_dialog_info_Sending_2_Sending_X_1xx(va_list *app) { - /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ - /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ + /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ + /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ - return 0; + return 0; } /* Sending -> (2xx) -> Sending */ int tsip_dialog_info_Sending_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - /* Reset curr action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + /* Reset curr action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - return 0; + return 0; } /* Sending -> (401/407/421/494) -> Sending */ int tsip_dialog_info_Sending_2_Sending_X_401_407_421_494(va_list *app) { - tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - int ret; - - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - // Alert the user - TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - return send_INFO(self); + tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + int ret; + + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + // Alert the user + TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return ret; + } + + return send_INFO(self); } /* Sending -> (300 to 699) -> Terminated */ int tsip_dialog_info_Sending_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response)); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response)); - /* Alert the user. */ - TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_INFO_SIGNAL(self, tsip_ao_info, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Sending -> (cancel) -> Terminated */ int tsip_dialog_info_Sending_2_Terminated_X_cancel(va_list *app) { - tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); - /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ + tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *); + /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ - /* RFC 3261 - 9.1 Client Behavior - A CANCEL request SHOULD NOT be sent to cancel a request other than INVITE. - */ + /* RFC 3261 - 9.1 Client Behavior + A CANCEL request SHOULD NOT be sent to cancel a request other than INVITE. + */ - /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed (worth nothing)) */ - tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); + /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed (worth nothing)) */ + tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "INFO cancelled"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "INFO cancelled"); - return 0; + return 0; } /* Receiving -> (accept) -> Terminated */ int tsip_dialog_info_Receiving_2_Terminated_X_accept(va_list *app) { - tsip_dialog_info_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_info_t *); - va_arg(*app, tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - if(!self->last_iMessage){ - TSK_DEBUG_ERROR("There is non INFO to accept()"); - /* Not an error ...but do not update current action */ - } - else{ - tsip_response_t *response; - int ret; - - /* curr_action is only used for outgoing requests */ - /* tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); */ - - /* send 200 OK */ - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", self->last_iMessage))){ - tsip_dialog_apply_action(response, action); /* apply action params to "this" response */ - if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), response))){ - TSK_DEBUG_ERROR("Failed to send SIP response."); - TSK_OBJECT_SAFE_FREE(response); - return ret; - } - TSK_OBJECT_SAFE_FREE(response); - } - else{ - TSK_DEBUG_ERROR("Failed to create SIP response."); - return -1; - } - } - - return 0; + tsip_dialog_info_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_info_t *); + va_arg(*app, tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + if(!self->last_iMessage) { + TSK_DEBUG_ERROR("There is non INFO to accept()"); + /* Not an error ...but do not update current action */ + } + else { + tsip_response_t *response; + int ret; + + /* curr_action is only used for outgoing requests */ + /* tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); */ + + /* send 200 OK */ + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", self->last_iMessage))) { + tsip_dialog_apply_action(response, action); /* apply action params to "this" response */ + if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), response))) { + TSK_DEBUG_ERROR("Failed to send SIP response."); + TSK_OBJECT_SAFE_FREE(response); + return ret; + } + TSK_OBJECT_SAFE_FREE(response); + } + else { + TSK_DEBUG_ERROR("Failed to create SIP response."); + return -1; + } + } + + return 0; } /* Receiving -> (reject) -> Terminated */ int tsip_dialog_info_Receiving_2_Terminated_X_reject(va_list *app) { - tsip_dialog_info_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_info_t *); - va_arg(*app, tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - if(!self->last_iMessage){ - TSK_DEBUG_ERROR("There is non INFO to reject()"); - /* Not an error ...but do not update current action */ - } - else{ - tsip_response_t *response; - int ret; - - /* curr_action is only used for outgoing requests */ - /* tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); */ - - /* send 486 Rejected */ - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 486, "Rejected", self->last_iMessage))){ - tsip_dialog_apply_action(response, action); /* apply action params to "this" response */ - if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), response))){ - TSK_DEBUG_ERROR("Failed to send SIP response."); - TSK_OBJECT_SAFE_FREE(response); - return ret; - } - TSK_OBJECT_SAFE_FREE(response); - } - else{ - TSK_DEBUG_ERROR("Failed to create SIP response."); - return -1; - } - } - - return 0; + tsip_dialog_info_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_info_t *); + va_arg(*app, tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + if(!self->last_iMessage) { + TSK_DEBUG_ERROR("There is non INFO to reject()"); + /* Not an error ...but do not update current action */ + } + else { + tsip_response_t *response; + int ret; + + /* curr_action is only used for outgoing requests */ + /* tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); */ + + /* send 486 Rejected */ + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 486, "Rejected", self->last_iMessage))) { + tsip_dialog_apply_action(response, action); /* apply action params to "this" response */ + if((ret = tsip_dialog_response_send(TSIP_DIALOG(self), response))) { + TSK_DEBUG_ERROR("Failed to send SIP response."); + TSK_OBJECT_SAFE_FREE(response); + return ret; + } + TSK_OBJECT_SAFE_FREE(response); + } + else { + TSK_DEBUG_ERROR("Failed to create SIP response."); + return -1; + } + } + + return 0; } /* Any -> (transport error) -> Terminated */ int tsip_dialog_info_Any_2_Terminated_X_transportError(va_list *app) { - /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } /* Any -> (error) -> Terminated */ int tsip_dialog_info_Any_2_Terminated_X_Error(va_list *app) { - /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_info_t *self = va_arg(*app, tsip_dialog_info_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -448,39 +441,39 @@ int tsip_dialog_info_Any_2_Terminated_X_Error(va_list *app) int send_INFO(tsip_dialog_info_t *self) { - tsip_request_t* request = tsk_null; - int ret = -1; + tsip_request_t* request = tsk_null; + int ret = -1; - if(!self){ - return -1; - } + if(!self) { + return -1; + } - if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))){ - return -2; - } + if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))) { + return -2; + } - /* apply action params to the request */ - if(TSIP_DIALOG(self)->curr_action){ - tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); - } + /* apply action params to the request */ + if(TSIP_DIALOG(self)->curr_action) { + tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); + } - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - TSK_OBJECT_SAFE_FREE(request); + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + TSK_OBJECT_SAFE_FREE(request); - return ret; + return ret; } int tsip_dialog_info_OnTerminated(tsip_dialog_info_t *self) { - TSK_DEBUG_INFO("=== INFO Dialog terminated ==="); + TSK_DEBUG_INFO("=== INFO Dialog terminated ==="); - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminated, - TSIP_DIALOG(self)->last_error.phrase ? TSIP_DIALOG(self)->last_error.phrase : "Dialog terminated"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminated, + TSIP_DIALOG(self)->last_error.phrase ? TSIP_DIALOG(self)->last_error.phrase : "Dialog terminated"); - /* Remove from the dialog layer. */ - return tsip_dialog_remove(TSIP_DIALOG(self)); + /* Remove from the dialog layer. */ + return tsip_dialog_remove(TSIP_DIALOG(self)); } @@ -509,48 +502,47 @@ int tsip_dialog_info_OnTerminated(tsip_dialog_info_t *self) // static tsk_object_t* tsip_dialog_info_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_info_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + tsip_dialog_info_t *dialog = self; + if(dialog) { + tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); - /* Initialize base class */ - tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_INFO, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_INFO, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); - /* FSM */ - TSIP_DIALOG_GET_FSM(self)->debug = DEBUG_STATE_MACHINE; - tsk_fsm_set_callback_terminated(TSIP_DIALOG_GET_FSM(self), TSK_FSM_ONTERMINATED_F(tsip_dialog_info_OnTerminated), (const void*)dialog); + /* FSM */ + TSIP_DIALOG_GET_FSM(self)->debug = DEBUG_STATE_MACHINE; + tsk_fsm_set_callback_terminated(TSIP_DIALOG_GET_FSM(self), TSK_FSM_ONTERMINATED_F(tsip_dialog_info_OnTerminated), (const void*)dialog); - /* Initialize the class itself */ - tsip_dialog_info_init(self); - } - return self; + /* Initialize the class itself */ + tsip_dialog_info_init(self); + } + return self; } static tsk_object_t* tsip_dialog_info_dtor(tsk_object_t * self) -{ - tsip_dialog_info_t *dialog = self; - if(dialog){ - /* DeInitialize base class (will cancel all transactions) */ - tsip_dialog_deinit(TSIP_DIALOG(self)); - - /* DeInitialize self */ - TSK_OBJECT_SAFE_FREE(dialog->last_iMessage); - - TSK_DEBUG_INFO("*** INFO Dialog destroyed ***"); - } - return self; +{ + tsip_dialog_info_t *dialog = self; + if(dialog) { + /* DeInitialize base class (will cancel all transactions) */ + tsip_dialog_deinit(TSIP_DIALOG(self)); + + /* DeInitialize self */ + TSK_OBJECT_SAFE_FREE(dialog->last_iMessage); + + TSK_DEBUG_INFO("*** INFO Dialog destroyed ***"); + } + return self; } static int tsip_dialog_info_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return tsip_dialog_cmp(obj1, obj2); + return tsip_dialog_cmp(obj1, obj2); } -static const tsk_object_def_t tsip_dialog_info_def_s = -{ - sizeof(tsip_dialog_info_t), - tsip_dialog_info_ctor, - tsip_dialog_info_dtor, - tsip_dialog_info_cmp, +static const tsk_object_def_t tsip_dialog_info_def_s = { + sizeof(tsip_dialog_info_t), + tsip_dialog_info_ctor, + tsip_dialog_info_dtor, + tsip_dialog_info_cmp, }; const tsk_object_def_t *tsip_dialog_info_def_t = &tsip_dialog_info_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.c b/tinySIP/src/dialogs/tsip_dialog_invite.c index ed7b3d5..73bbb2d 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.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. * @@ -70,7 +70,7 @@ // 3GPP TS 26.114 (MMTel): Media handling and interaction // 3GPP TS 24.173 (MMTel): Supplementary Services // -/* ======================== MMTel Supplementary Services ======================== +/* ======================== MMTel Supplementary Services ======================== 3GPP TS 24.607 : Originating Identification Presentation 3GPP TS 24.608 : Terminating Identification Presentation 3GPP TS 24.607 : Originating Identification Restriction @@ -78,14 +78,14 @@ 3GPP TS 24.604 : Communication Diversion Unconditional 3GPP TS 24.604 : Communication Diversion on not Logged -3GPP TS 24.604 : Communication Diversion on Busy +3GPP TS 24.604 : Communication Diversion on Busy 3GPP TS 24.604 : Communication Diversion on not Reachable 3GPP TS 24.604 : Communication Diversion on No Reply 3GPP TS 24.611 : Barring of All Incoming Calls 3GPP TS 24.611 : Barring of All Outgoing Calls 3GPP TS 24.611 : Barring of Outgoing International Calls 3GPP TS 24.611 : Barring of Incoming Calls - When Roaming -3GPP TS 24.610 : Communication Hold +3GPP TS 24.610 : Communication Hold 3GPP TS 24.606 : Message Waiting Indication 3GPP TS 24.615 : Communication Waiting 3GPP TS 24.605 : Ad-Hoc Multi Party Conference @@ -150,23 +150,23 @@ static int x9999_Any_2_Any_X_Error(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_is_resp2INVITE(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_INVITE(message); + return TSIP_RESPONSE_IS_TO_INVITE(message); } static tsk_bool_t _fsm_cond_is_resp2UPDATE(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_UPDATE(message); + return TSIP_RESPONSE_IS_TO_UPDATE(message); } static tsk_bool_t _fsm_cond_is_resp2BYE(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_BYE(message); + return TSIP_RESPONSE_IS_TO_BYE(message); } static tsk_bool_t _fsm_cond_is_resp2PRACK(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_PRACK(message); + return TSIP_RESPONSE_IS_TO_PRACK(message); } static tsk_bool_t _fsm_cond_is_resp2INFO(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_INFO(message); + return TSIP_RESPONSE_IS_TO_INFO(message); } /* ======================== actions ======================== */ @@ -192,352 +192,348 @@ extern int tsip_dialog_invite_qos_init(tsip_dialog_invite_t *self); int tsip_dialog_invite_event_callback(const tsip_dialog_invite_t *self, tsip_dialog_event_type_t type, const tsip_message_t *msg) { - int ret = -1; - - switch(type) - { - case tsip_dialog_i_msg: - { - if(msg){ - if(TSIP_MESSAGE_IS_RESPONSE(msg)){ /* Response */ - const tsip_action_t* action = tsip_dialog_keep_action(TSIP_DIALOG(self), msg) ? TSIP_DIALOG(self)->curr_action : tsk_null; - if(TSIP_RESPONSE_IS_1XX(msg)){ // 100-199 - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i1xx, msg, action); - } - else if(TSIP_RESPONSE_IS_2XX(msg)){ // 200-299 - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i2xx, msg, action); - } - else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407){ // 401,407 - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i401_i407, msg, action); - } - else if(TSIP_RESPONSE_CODE(msg) == 422){ // 422 - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i422, msg, action); - } - else if(TSIP_RESPONSE_IS_3456(msg)){ // 300-699 - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i300_to_i699, msg, action); - } - else; // Ignore - } - else{ /* Request */ - if(TSIP_REQUEST_IS_INVITE(msg)){ // INVITE - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iINVITE, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_UPDATE(msg)){ // UPDATE - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iUPDATE, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_PRACK(msg)){ // PRACK - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iPRACK, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_ACK(msg)){ // ACK - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iACK, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_OPTIONS(msg)){ // OPTIONS - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iOPTIONS, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_BYE(msg)){ // BYE - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iBYE, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_CANCEL(msg)){ // CANCEL - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iCANCEL, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_INFO(msg)){ // INFO - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iINFO, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_NOTIFY(msg)){ // NOTIFY - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iNOTIFY, msg, tsk_null); - } - else if(TSIP_REQUEST_IS_REFER(msg)){ // REFER - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iREFER, msg, tsk_null); - } - } - } - break; - } - - case tsip_dialog_canceled: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oCANCEL, msg, tsk_null); - break; - } - - case tsip_dialog_timedout: - { - // Do nothing if request type is "INFO" - if(!TSIP_MESSAGE_IS_REQUEST(msg) || !TSIP_REQUEST_IS_INFO(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); - } - break; - } - case tsip_dialog_terminated: - case tsip_dialog_error: - case tsip_dialog_transport_error: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); - break; - } - - default: break; - } - - return ret; + int ret = -1; + + switch(type) { + case tsip_dialog_i_msg: { + if(msg) { + if(TSIP_MESSAGE_IS_RESPONSE(msg)) { /* Response */ + const tsip_action_t* action = tsip_dialog_keep_action(TSIP_DIALOG(self), msg) ? TSIP_DIALOG(self)->curr_action : tsk_null; + if(TSIP_RESPONSE_IS_1XX(msg)) { // 100-199 + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i1xx, msg, action); + } + else if(TSIP_RESPONSE_IS_2XX(msg)) { // 200-299 + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i2xx, msg, action); + } + else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407) { // 401,407 + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i401_i407, msg, action); + } + else if(TSIP_RESPONSE_CODE(msg) == 422) { // 422 + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i422, msg, action); + } + else if(TSIP_RESPONSE_IS_3456(msg)) { // 300-699 + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_i300_to_i699, msg, action); + } + else; // Ignore + } + else { /* Request */ + if(TSIP_REQUEST_IS_INVITE(msg)) { // INVITE + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iINVITE, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_UPDATE(msg)) { // UPDATE + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iUPDATE, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_PRACK(msg)) { // PRACK + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iPRACK, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_ACK(msg)) { // ACK + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iACK, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_OPTIONS(msg)) { // OPTIONS + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iOPTIONS, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_BYE(msg)) { // BYE + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iBYE, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_CANCEL(msg)) { // CANCEL + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iCANCEL, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_INFO(msg)) { // INFO + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iINFO, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_NOTIFY(msg)) { // NOTIFY + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iNOTIFY, msg, tsk_null); + } + else if(TSIP_REQUEST_IS_REFER(msg)) { // REFER + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iREFER, msg, tsk_null); + } + } + } + break; + } + + case tsip_dialog_canceled: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oCANCEL, msg, tsk_null); + break; + } + + case tsip_dialog_timedout: { + // Do nothing if request type is "INFO" + if(!TSIP_MESSAGE_IS_REQUEST(msg) || !TSIP_REQUEST_IS_INFO(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); + } + break; + } + case tsip_dialog_terminated: + case tsip_dialog_error: + case tsip_dialog_transport_error: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); + break; + } + + default: + break; + } + + return ret; } /**Timer manager callback. * - * @param self The owner of the signaled timer. + * @param self The owner of the signaled timer. * @param timer_id The identifier of the signaled timer. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_invite_timer_callback(const tsip_dialog_invite_t* self, tsk_timer_id_t timer_id) { - int ret = -1; - - if(self){ - if(timer_id == self->stimers.timer.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timerRefresh, tsk_null, tsk_null); - } - else if(timer_id == self->timer100rel.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timer100rel, tsk_null, tsk_null); - } - else if(timer_id == self->qos.timer.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timerRSVP, tsk_null, tsk_null); - } - else if(timer_id == self->timershutdown.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_shutdown_timedout, tsk_null, tsk_null); - } - } - return ret; + int ret = -1; + + if(self) { + if(timer_id == self->stimers.timer.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timerRefresh, tsk_null, tsk_null); + } + else if(timer_id == self->timer100rel.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timer100rel, tsk_null, tsk_null); + } + else if(timer_id == self->qos.timer.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_timerRSVP, tsk_null, tsk_null); + } + else if(timer_id == self->timershutdown.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_shutdown_timedout, tsk_null, tsk_null); + } + } + return ret; } tsip_dialog_invite_t* tsip_dialog_invite_create(const tsip_ssession_handle_t* ss, const char* call_id) { - return tsk_object_new(tsip_dialog_invite_def_t, ss, call_id); + return tsk_object_new(tsip_dialog_invite_def_t, ss, call_id); } int tsip_dialog_invite_init(tsip_dialog_invite_t *self) { - /* special cases (fsm) should be tried first */ - - /* ICE */ - tsip_dialog_invite_ice_init(self); - /* Client-Side dialog */ - tsip_dialog_invite_client_init(self); - /* Server-Side dialog */ - tsip_dialog_invite_server_init(self); - /* 3GPP TS 24.610: Communication Hold */ - tsip_dialog_invite_hold_init(self); - /* 3GPP TS 24.629: Explicit Communication Transfer (ECT) using IP Multimedia (IM) Core Network (CN) subsystem */ - tsip_dialog_invite_ect_init(self); - /* RFC 4028: Session Timers */ - tsip_dialog_invite_stimers_init(self); - /* RFC 3312: Integration of Resource Management and Session Initiation Protocol (SIP) */ - tsip_dialog_invite_qos_init(self); - - /* Initialize the state machine (all other cases) */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_invite_Started_2_Started_X_any"), - - /*======================= - * === Connected === - */ - // Connected -> (Send DTMF) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_dtmf_send, _fsm_state_Connected, x0000_Connected_2_Connected_X_oDTMF, "x0000_Connected_2_Connected_X_oDTMF"), - // Connected -> (Send MSRP message) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_msrp_send_msg, _fsm_state_Connected, x0000_Connected_2_Connected_X_oLMessage, "x0000_Connected_2_Connected_X_oLMessage"), - // Connected -> (iACK) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iACK, _fsm_state_Connected, x0000_Connected_2_Connected_X_iACK, "x0000_Connected_2_Connected_X_iACK"), - // Connected -> (iINVITE) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iINVITE, _fsm_state_Connected, x0000_Connected_2_Connected_X_iINVITEorUPDATE, "x0000_Connected_2_Connected_X_iINVITE"), - // Connected -> (iUPDATE) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iUPDATE, _fsm_state_Connected, x0000_Connected_2_Connected_X_iINVITEorUPDATE, "x0000_Connected_2_Connected_X_iUPDATE"), - // Connected -> (send reINVITE) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oINVITE, _fsm_state_Connected, x0000_Connected_2_Connected_X_oINVITE, "x0000_Connected_2_Connected_X_oINVITE"), - - /*======================= - * === BYE/SHUTDOWN === - */ - // Any -> (oBYE) -> Trying - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oBYE, _fsm_state_Trying, x0000_Any_2_Trying_X_oBYE, "x0000_Any_2_Trying_X_oBYE"), - // Any -> (iBYE) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iBYE, _fsm_state_Terminated, x0000_Any_2_Terminated_X_iBYE, "x0000_Any_2_Terminated_X_iBYE"), - // Any -> (i401/407 BYE) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2BYE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), - // Any -> (i3xx-i6xx BYE) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i300_to_i699, _fsm_cond_is_resp2BYE, _fsm_state_Terminated, tsk_null, "x0000_Any_2_Terminated_X_i3xxTOi6xxBYE"), - // Any -> (i2xxx BYE) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2BYE, _fsm_state_Terminated, tsk_null, "x0000_Any_2_Terminated_X_i2xxBYE"), - // Any -> (Shutdown) -> Trying - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oShutdown, _fsm_state_Trying, x0000_Any_2_Trying_X_shutdown, "x0000_Any_2_Trying_X_shutdown"), - // Any -> (shutdown timedout) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_invite_shutdown_timedout"), - - - /*======================= - * === Any === - */ - // Any -> (i1xx) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_i1xx, tsk_fsm_state_any, x0000_Any_2_Any_X_i1xx, "x0000_Any_2_Any_X_i1xx"), - // Any -> (oINFO) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oINFO, tsk_fsm_state_any, x0000_Any_2_Any_X_oINFO, "x0000_Any_2_Any_X_oINFO"), - // Any -> (iINFO) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iINFO, tsk_fsm_state_any, x0000_Any_2_Any_X_iINFO, "x0000_Any_2_Any_X_iINFO"), - // Any -> (i401/407) - // - // Any -> (iPRACK) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iPRACK, tsk_fsm_state_any, x0000_Any_2_Any_X_iPRACK, "x0000_Any_2_Any_X_iPRACK"), - // Any -> (iOPTIONS) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iOPTIONS, tsk_fsm_state_any, x0000_Any_2_Any_X_iOPTIONS, "x0000_Any_2_Any_X_iOPTIONS"), - // Any -> (i2xx INVITE) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2INVITE, tsk_fsm_state_any, x0000_Any_2_Any_X_i2xxINVITEorUPDATE, "x0000_Any_2_Any_X_i2xxINVITE"), - // Any -> (i2xx UPDATE) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2UPDATE, tsk_fsm_state_any, x0000_Any_2_Any_X_i2xxINVITEorUPDATE, "x0000_Any_2_Any_X_i2xxUPDATE"), - // Any -> (i401/407 INVITE) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2INVITE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), - // Any -> (i401/407 UPDATE) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2UPDATE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), - // Any -> (i2xx PRACK) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2PRACK, tsk_fsm_state_any, tsk_null, "x0000_Any_2_Any_X_i2xxPRACK"), - // Any -> (i2xx INFO) -> Any - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2INFO, tsk_fsm_state_any, tsk_null, "x0000_Any_2_Any_X_i2xxINFO"), - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, x9998_Any_2_Terminated_X_transportError, "x9998_Any_2_Terminated_X_transportError"), - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, x9999_Any_2_Any_X_Error, "x9999_Any_2_Any_X_Error"), - - TSK_FSM_ADD_NULL()); - - /* Sets callback function */ - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_invite_event_callback); - - /* Timers */ - self->timer100rel.id = TSK_INVALID_TIMER_ID; - self->stimers.timer.id = TSK_INVALID_TIMER_ID; - self->timershutdown.id = TSK_INVALID_TIMER_ID; - self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; - - return 0; + /* special cases (fsm) should be tried first */ + + /* ICE */ + tsip_dialog_invite_ice_init(self); + /* Client-Side dialog */ + tsip_dialog_invite_client_init(self); + /* Server-Side dialog */ + tsip_dialog_invite_server_init(self); + /* 3GPP TS 24.610: Communication Hold */ + tsip_dialog_invite_hold_init(self); + /* 3GPP TS 24.629: Explicit Communication Transfer (ECT) using IP Multimedia (IM) Core Network (CN) subsystem */ + tsip_dialog_invite_ect_init(self); + /* RFC 4028: Session Timers */ + tsip_dialog_invite_stimers_init(self); + /* RFC 3312: Integration of Resource Management and Session Initiation Protocol (SIP) */ + tsip_dialog_invite_qos_init(self); + + /* Initialize the state machine (all other cases) */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_invite_Started_2_Started_X_any"), + + /*======================= + * === Connected === + */ + // Connected -> (Send DTMF) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_dtmf_send, _fsm_state_Connected, x0000_Connected_2_Connected_X_oDTMF, "x0000_Connected_2_Connected_X_oDTMF"), + // Connected -> (Send MSRP message) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_msrp_send_msg, _fsm_state_Connected, x0000_Connected_2_Connected_X_oLMessage, "x0000_Connected_2_Connected_X_oLMessage"), + // Connected -> (iACK) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iACK, _fsm_state_Connected, x0000_Connected_2_Connected_X_iACK, "x0000_Connected_2_Connected_X_iACK"), + // Connected -> (iINVITE) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iINVITE, _fsm_state_Connected, x0000_Connected_2_Connected_X_iINVITEorUPDATE, "x0000_Connected_2_Connected_X_iINVITE"), + // Connected -> (iUPDATE) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iUPDATE, _fsm_state_Connected, x0000_Connected_2_Connected_X_iINVITEorUPDATE, "x0000_Connected_2_Connected_X_iUPDATE"), + // Connected -> (send reINVITE) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oINVITE, _fsm_state_Connected, x0000_Connected_2_Connected_X_oINVITE, "x0000_Connected_2_Connected_X_oINVITE"), + + /*======================= + * === BYE/SHUTDOWN === + */ + // Any -> (oBYE) -> Trying + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oBYE, _fsm_state_Trying, x0000_Any_2_Trying_X_oBYE, "x0000_Any_2_Trying_X_oBYE"), + // Any -> (iBYE) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iBYE, _fsm_state_Terminated, x0000_Any_2_Terminated_X_iBYE, "x0000_Any_2_Terminated_X_iBYE"), + // Any -> (i401/407 BYE) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2BYE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), + // Any -> (i3xx-i6xx BYE) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i300_to_i699, _fsm_cond_is_resp2BYE, _fsm_state_Terminated, tsk_null, "x0000_Any_2_Terminated_X_i3xxTOi6xxBYE"), + // Any -> (i2xxx BYE) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2BYE, _fsm_state_Terminated, tsk_null, "x0000_Any_2_Terminated_X_i2xxBYE"), + // Any -> (Shutdown) -> Trying + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oShutdown, _fsm_state_Trying, x0000_Any_2_Trying_X_shutdown, "x0000_Any_2_Trying_X_shutdown"), + // Any -> (shutdown timedout) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_invite_shutdown_timedout"), + + + /*======================= + * === Any === + */ + // Any -> (i1xx) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_i1xx, tsk_fsm_state_any, x0000_Any_2_Any_X_i1xx, "x0000_Any_2_Any_X_i1xx"), + // Any -> (oINFO) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_oINFO, tsk_fsm_state_any, x0000_Any_2_Any_X_oINFO, "x0000_Any_2_Any_X_oINFO"), + // Any -> (iINFO) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iINFO, tsk_fsm_state_any, x0000_Any_2_Any_X_iINFO, "x0000_Any_2_Any_X_iINFO"), + // Any -> (i401/407) + // + // Any -> (iPRACK) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iPRACK, tsk_fsm_state_any, x0000_Any_2_Any_X_iPRACK, "x0000_Any_2_Any_X_iPRACK"), + // Any -> (iOPTIONS) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_iOPTIONS, tsk_fsm_state_any, x0000_Any_2_Any_X_iOPTIONS, "x0000_Any_2_Any_X_iOPTIONS"), + // Any -> (i2xx INVITE) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2INVITE, tsk_fsm_state_any, x0000_Any_2_Any_X_i2xxINVITEorUPDATE, "x0000_Any_2_Any_X_i2xxINVITE"), + // Any -> (i2xx UPDATE) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2UPDATE, tsk_fsm_state_any, x0000_Any_2_Any_X_i2xxINVITEorUPDATE, "x0000_Any_2_Any_X_i2xxUPDATE"), + // Any -> (i401/407 INVITE) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2INVITE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), + // Any -> (i401/407 UPDATE) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i401_i407, _fsm_cond_is_resp2UPDATE, tsk_fsm_state_any, x0000_Any_2_Any_X_i401_407_Challenge, "x0000_Any_2_Any_X_i401_407_Challenge"), + // Any -> (i2xx PRACK) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2PRACK, tsk_fsm_state_any, tsk_null, "x0000_Any_2_Any_X_i2xxPRACK"), + // Any -> (i2xx INFO) -> Any + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_i2xx, _fsm_cond_is_resp2INFO, tsk_fsm_state_any, tsk_null, "x0000_Any_2_Any_X_i2xxINFO"), + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, x9998_Any_2_Terminated_X_transportError, "x9998_Any_2_Terminated_X_transportError"), + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, x9999_Any_2_Any_X_Error, "x9999_Any_2_Any_X_Error"), + + TSK_FSM_ADD_NULL()); + + /* Sets callback function */ + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_invite_event_callback); + + /* Timers */ + self->timer100rel.id = TSK_INVALID_TIMER_ID; + self->stimers.timer.id = TSK_INVALID_TIMER_ID; + self->timershutdown.id = TSK_INVALID_TIMER_ID; + self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; + + return 0; } // start sending int tsip_dialog_invite_start(tsip_dialog_invite_t *self) { - int ret = -1; - if(self && !TSIP_DIALOG(self)->running){ - if(!(ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oINVITE, tsk_null, tsk_null))){ - TSIP_DIALOG(self)->running = tsk_true; - } - } - return ret; + int ret = -1; + if(self && !TSIP_DIALOG(self)->running) { + if(!(ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oINVITE, tsk_null, tsk_null))) { + TSIP_DIALOG(self)->running = tsk_true; + } + } + return ret; } int tsip_dialog_invite_process_ro(tsip_dialog_invite_t *self, const tsip_message_t* message) { - tsdp_message_t* sdp_ro = tsk_null; - tmedia_type_t old_media_type; - tmedia_type_t new_media_type; - tsk_bool_t media_session_was_null; - int ret = 0; - tmedia_ro_type_t ro_type = tmedia_ro_type_none; - - if(!self || !message){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - + tsdp_message_t* sdp_ro = tsk_null; + tmedia_type_t old_media_type; + tmedia_type_t new_media_type; + tsk_bool_t media_session_was_null; + int ret = 0; + tmedia_ro_type_t ro_type = tmedia_ro_type_none; + + if(!self || !message) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (self->is_cancelling) { TSK_DEBUG_INFO("Cancelling the INVITE...ignore the incoming SDP"); return 0; } - /* Parse SDP content */ - if(TSIP_MESSAGE_HAS_CONTENT(message)){ - if(tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))){ - if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))){ - TSK_DEBUG_ERROR("Failed to parse remote sdp message:\n [%s]", (const char*)TSIP_MESSAGE_CONTENT_DATA(message)); - return -2; - } - // ICE processing - if(self->supported.ice){ - tsip_dialog_invite_ice_process_ro(self, sdp_ro, TSIP_MESSAGE_IS_REQUEST(message)); - } - } - else{ - TSK_DEBUG_ERROR("[%s] content-type is not supportted", TSIP_MESSAGE_CONTENT_TYPE(message)); - return -3; - } - } - else{ - if(TSIP_DIALOG(self)->state == tsip_initial && TSIP_REQUEST_IS_INVITE(message)){ /* Bodiless initial INVITE */ - TSIP_DIALOG_GET_SS(self)->media.type = tmedia_defaults_get_media_type(); // Default media for initial INVITE to send with the first reliable answer - } - else{ - return 0; - } - } - - ro_type = (TSIP_REQUEST_IS_INVITE(message) || TSIP_REQUEST_IS_UPDATE(message)) // ACK/PRACK can only contain a response if the initial INVITE was bodiless - ? tmedia_ro_type_offer - :(TSIP_RESPONSE_IS_1XX(message) ? tmedia_ro_type_provisional : tmedia_ro_type_answer); - media_session_was_null = (self->msession_mgr == tsk_null); - old_media_type = TSIP_DIALOG_GET_SS(self)->media.type; - new_media_type = sdp_ro ? tmedia_type_from_sdp(sdp_ro) : old_media_type; - - /* Create session Manager if not already done */ - if(!self->msession_mgr){ - int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; - TSIP_DIALOG_GET_SS(self)->media.type = new_media_type; - self->msession_mgr = tmedia_session_mgr_create(TSIP_DIALOG_GET_SS(self)->media.type, TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], - TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), (sdp_ro == tsk_null)); - if(TSIP_DIALOG_GET_STACK(self)->natt.ctx){ - tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]); - } - ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); - } - - if(sdp_ro){ - if (tmedia_session_mgr_is_new_ro(self->msession_mgr, sdp_ro)) { - ret = tsip_dialog_invite_msession_configure(self); - } - if((ret = tmedia_session_mgr_set_ro(self->msession_mgr, sdp_ro, ro_type))){ - TSK_DEBUG_ERROR("Failed to set remote offer"); - goto bail; - } - } - - // is media update? - // (old_media_type == new_media_type) means the new session are rejected. This is way we match the CSeq - if(!media_session_was_null && (old_media_type != new_media_type || (TSIP_MESSAGE_IS_RESPONSE(message) && self->cseq_out_media_update == message->CSeq->seq)) && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)){ - // at this point the media session manager has been succeffuly started and all is ok - TSIP_DIALOG_GET_SS(self)->media.type = new_media_type; - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_updated, - TSIP_RESPONSE_CODE(message), TSIP_RESPONSE_PHRASE(message), message); - } - - /* start session manager */ - if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)){ - /* Set MSRP Callback */ - if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp){ - tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); - } - /* starts session manager*/ - ret = tsip_dialog_invite_msession_start(self); - - if(ret == 0 && TSIP_DIALOG(self)->state == tsip_early){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_early_media, - TSIP_RESPONSE_CODE(message), TSIP_RESPONSE_PHRASE(message), message); - } - } - + /* Parse SDP content */ + if(TSIP_MESSAGE_HAS_CONTENT(message)) { + if(tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))) { + if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))) { + TSK_DEBUG_ERROR("Failed to parse remote sdp message:\n [%s]", (const char*)TSIP_MESSAGE_CONTENT_DATA(message)); + return -2; + } + // ICE processing + if(self->supported.ice) { + tsip_dialog_invite_ice_process_ro(self, sdp_ro, TSIP_MESSAGE_IS_REQUEST(message)); + } + } + else { + TSK_DEBUG_ERROR("[%s] content-type is not supportted", TSIP_MESSAGE_CONTENT_TYPE(message)); + return -3; + } + } + else { + if(TSIP_DIALOG(self)->state == tsip_initial && TSIP_REQUEST_IS_INVITE(message)) { /* Bodiless initial INVITE */ + TSIP_DIALOG_GET_SS(self)->media.type = tmedia_defaults_get_media_type(); // Default media for initial INVITE to send with the first reliable answer + } + else { + return 0; + } + } + + ro_type = (TSIP_REQUEST_IS_INVITE(message) || TSIP_REQUEST_IS_UPDATE(message)) // ACK/PRACK can only contain a response if the initial INVITE was bodiless + ? tmedia_ro_type_offer + :(TSIP_RESPONSE_IS_1XX(message) ? tmedia_ro_type_provisional : tmedia_ro_type_answer); + media_session_was_null = (self->msession_mgr == tsk_null); + old_media_type = TSIP_DIALOG_GET_SS(self)->media.type; + new_media_type = sdp_ro ? tmedia_type_from_sdp(sdp_ro) : old_media_type; + + /* Create session Manager if not already done */ + if(!self->msession_mgr) { + int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; + TSIP_DIALOG_GET_SS(self)->media.type = new_media_type; + self->msession_mgr = tmedia_session_mgr_create(TSIP_DIALOG_GET_SS(self)->media.type, TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], + TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), (sdp_ro == tsk_null)); + if(TSIP_DIALOG_GET_STACK(self)->natt.ctx) { + tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]); + } + ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); + } + + if(sdp_ro) { + if (tmedia_session_mgr_is_new_ro(self->msession_mgr, sdp_ro)) { + ret = tsip_dialog_invite_msession_configure(self); + } + if((ret = tmedia_session_mgr_set_ro(self->msession_mgr, sdp_ro, ro_type))) { + TSK_DEBUG_ERROR("Failed to set remote offer"); + goto bail; + } + } + + // is media update? + // (old_media_type == new_media_type) means the new session are rejected. This is way we match the CSeq + if(!media_session_was_null && (old_media_type != new_media_type || (TSIP_MESSAGE_IS_RESPONSE(message) && self->cseq_out_media_update == message->CSeq->seq)) && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)) { + // at this point the media session manager has been succeffuly started and all is ok + TSIP_DIALOG_GET_SS(self)->media.type = new_media_type; + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_updated, + TSIP_RESPONSE_CODE(message), TSIP_RESPONSE_PHRASE(message), message); + } + + /* start session manager */ + if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)) { + /* Set MSRP Callback */ + if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp) { + tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); + } + /* starts session manager*/ + ret = tsip_dialog_invite_msession_start(self); + + if(ret == 0 && TSIP_DIALOG(self)->state == tsip_early) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_early_media, + TSIP_RESPONSE_CODE(message), TSIP_RESPONSE_PHRASE(message), message); + } + } + bail: - TSK_OBJECT_SAFE_FREE(sdp_ro); + TSK_OBJECT_SAFE_FREE(sdp_ro); - return ret; + return ret; } @@ -547,520 +543,520 @@ bail: int x0000_Connected_2_Connected_X_oDTMF(va_list *app) { - int ret; - 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 *); - - if(action){ - ret = tmedia_session_mgr_send_dtmf(self->msession_mgr, action->dtmf.event); - } - else{ - TSK_DEBUG_ERROR("Invalid action"); - } - - return 0; /* always */ + int ret; + 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 *); + + if(action) { + ret = tmedia_session_mgr_send_dtmf(self->msession_mgr, action->dtmf.event); + } + else { + TSK_DEBUG_ERROR("Invalid action"); + } + + return 0; /* always */ } int x0000_Connected_2_Connected_X_oLMessage(va_list *app) { - int ret; - 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 *); - - if(action && action->payload){ - ret = tmedia_session_mgr_send_message(self->msession_mgr, action->payload->data, action->payload->size, - action->media.params); - } - else{ - TSK_DEBUG_ERROR("Invalid action"); - } - - return 0; + int ret; + 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 *); + + if(action && action->payload) { + ret = tmedia_session_mgr_send_message(self->msession_mgr, action->payload->data, action->payload->size, + action->media.params); + } + else { + TSK_DEBUG_ERROR("Invalid action"); + } + + return 0; } /* Connected -> (iACK) -> Connected */ int x0000_Connected_2_Connected_X_iACK(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rACK = va_arg(*app, const tsip_request_t *); - int ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rACK = va_arg(*app, const tsip_request_t *); + int ret; + + // Nothing to do (in future will be used to ensure the session) - // Nothing to do (in future will be used to ensure the session) - /* No longer waiting for the initial ACK */ self->is_initial_iack_pending = tsk_false; - - /* Process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, rACK))){ - /* Send error */ - return ret; - } - - /* Starts media session if not already done */ - if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)){ - ret = tsip_dialog_invite_msession_start(self); - } - - // starts ICE timers now that both parties receive the "candidates" - if(tsip_dialog_invite_ice_is_enabled(self)){ - tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); - } - - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request", rACK); - - return 0; + + /* Process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, rACK))) { + /* Send error */ + return ret; + } + + /* Starts media session if not already done */ + if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)) { + ret = tsip_dialog_invite_msession_start(self); + } + + // starts ICE timers now that both parties receive the "candidates" + if(tsip_dialog_invite_ice_is_enabled(self)) { + tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); + } + + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request", rACK); + + return 0; } /* Connected -> (iINVITE or iUPDATE) -> Connected */ int x0000_Connected_2_Connected_X_iINVITEorUPDATE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rINVITEorUPDATE = va_arg(*app, const tsip_request_t *); - - int ret = 0; - tsk_bool_t bodiless_invite; - tmedia_type_t old_media_type = self->msession_mgr ? self->msession_mgr->type : tmedia_none; - tmedia_type_t new_media_type; - tsk_bool_t force_sdp; - - /* process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, rINVITEorUPDATE))){ - /* Send error */ - return ret; - } - - // force SDP in 200 OK even if the request has the same SDP version - force_sdp = TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE); - - // get new media_type after processing the remote offer - new_media_type = self->msession_mgr ? self->msession_mgr->type : tmedia_none; - - /** response to bodiless iINVITE always contains SDP as explained below - RFC3261 - 14.1 UAC Behavior - The same offer-answer model that applies to session descriptions in - INVITEs (Section 13.2.1) applies to re-INVITEs. As a result, a UAC - that wants to add a media stream, for example, will create a new - offer that contains this media stream, and send that in an INVITE - request to its peer. It is important to note that the full - description of the session, not just the change, is sent. This - supports stateless session processing in various elements, and - supports failover and recovery capabilities. Of course, a UAC MAY - send a re-INVITE with no session description, in which case the first - reliable non-failure response to the re-INVITE will contain the offer - (in this specification, that is a 2xx response). - */ - bodiless_invite = !TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE) && TSIP_REQUEST_IS_INVITE(rINVITEorUPDATE); - - /* session timers (must be before sending response) */ - if(self->stimers.timer.timeout){ - tsip_dialog_invite_stimers_handle(self, rINVITEorUPDATE); - } - - /* hold/resume */ - tsip_dialog_invite_hold_handle(self, rINVITEorUPDATE); - - // send the response - ret = send_RESPONSE(self, rINVITEorUPDATE, 200, "OK", - (self->msession_mgr && (force_sdp || bodiless_invite || self->msession_mgr->ro_changed || self->msession_mgr->state_changed || (old_media_type != new_media_type)))); - - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request.", rINVITEorUPDATE); - - return ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rINVITEorUPDATE = va_arg(*app, const tsip_request_t *); + + int ret = 0; + tsk_bool_t bodiless_invite; + tmedia_type_t old_media_type = self->msession_mgr ? self->msession_mgr->type : tmedia_none; + tmedia_type_t new_media_type; + tsk_bool_t force_sdp; + + /* process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, rINVITEorUPDATE))) { + /* Send error */ + return ret; + } + + // force SDP in 200 OK even if the request has the same SDP version + force_sdp = TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE); + + // get new media_type after processing the remote offer + new_media_type = self->msession_mgr ? self->msession_mgr->type : tmedia_none; + + /** response to bodiless iINVITE always contains SDP as explained below + RFC3261 - 14.1 UAC Behavior + The same offer-answer model that applies to session descriptions in + INVITEs (Section 13.2.1) applies to re-INVITEs. As a result, a UAC + that wants to add a media stream, for example, will create a new + offer that contains this media stream, and send that in an INVITE + request to its peer. It is important to note that the full + description of the session, not just the change, is sent. This + supports stateless session processing in various elements, and + supports failover and recovery capabilities. Of course, a UAC MAY + send a re-INVITE with no session description, in which case the first + reliable non-failure response to the re-INVITE will contain the offer + (in this specification, that is a 2xx response). + */ + bodiless_invite = !TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE) && TSIP_REQUEST_IS_INVITE(rINVITEorUPDATE); + + /* session timers (must be before sending response) */ + if(self->stimers.timer.timeout) { + tsip_dialog_invite_stimers_handle(self, rINVITEorUPDATE); + } + + /* hold/resume */ + tsip_dialog_invite_hold_handle(self, rINVITEorUPDATE); + + // send the response + ret = send_RESPONSE(self, rINVITEorUPDATE, 200, "OK", + (self->msession_mgr && (force_sdp || bodiless_invite || self->msession_mgr->ro_changed || self->msession_mgr->state_changed || (old_media_type != new_media_type)))); + + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request.", rINVITEorUPDATE); + + return ret; } /* Connected -> (send reINVITE) -> Connected */ static int x0000_Connected_2_Connected_X_oINVITE(va_list *app) { - int ret; - tsk_bool_t mediaType_changed; - 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 *); - - /* Get Media type from the action */ - mediaType_changed = (TSIP_DIALOG_GET_SS(self)->media.type != action->media.type && action->media.type != tmedia_none); - if (mediaType_changed){ - if (self->msession_mgr) { - ret = tmedia_session_mgr_set_media_type(self->msession_mgr, action->media.type); - } - self->cseq_out_media_update = TSIP_DIALOG(self)->cseq_value + 1; - } - - /* 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); - } - - /* send the request */ - ret = send_INVITE(self, mediaType_changed); - - /* alert the user */ - if(mediaType_changed){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_updating, - tsip_event_code_dialog_request_outgoing, "Updating media type", self->last_oInvite); - } - - return ret; + int ret; + tsk_bool_t mediaType_changed; + 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 *); + + /* Get Media type from the action */ + mediaType_changed = (TSIP_DIALOG_GET_SS(self)->media.type != action->media.type && action->media.type != tmedia_none); + if (mediaType_changed) { + if (self->msession_mgr) { + ret = tmedia_session_mgr_set_media_type(self->msession_mgr, action->media.type); + } + self->cseq_out_media_update = TSIP_DIALOG(self)->cseq_value + 1; + } + + /* 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); + } + + /* send the request */ + ret = send_INVITE(self, mediaType_changed); + + /* alert the user */ + if(mediaType_changed) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_updating, + tsip_event_code_dialog_request_outgoing, "Updating media type", self->last_oInvite); + } + + return ret; } /* Any -> (iPRACK) -> Any */ int x0000_Any_2_Any_X_iPRACK(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rPRACK = va_arg(*app, const tsip_request_t *); - - const tsip_header_RAck_t* RAck; - - if((RAck = (const tsip_header_RAck_t*)tsip_message_get_header(rPRACK, 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 send_RESPONSE(self, rPRACK, 200, "OK", tsk_false); - } - } - - /* Send 488 */ - return send_ERROR(self, rPRACK, 488, "Failed to match PRACK request", "SIP; cause=488; text=\"Failed to match PRACK request\""); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rPRACK = va_arg(*app, const tsip_request_t *); + + const tsip_header_RAck_t* RAck; + + if((RAck = (const tsip_header_RAck_t*)tsip_message_get_header(rPRACK, 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 send_RESPONSE(self, rPRACK, 200, "OK", tsk_false); + } + } + + /* Send 488 */ + return send_ERROR(self, rPRACK, 488, "Failed to match PRACK request", "SIP; cause=488; text=\"Failed to match PRACK request\""); } /* Any -> (iOPTIONS) -> Any */ int x0000_Any_2_Any_X_iOPTIONS(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rOPTIONS = va_arg(*app, const tsip_request_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rOPTIONS = va_arg(*app, const tsip_request_t *); - /* Alert user */ + /* Alert user */ - /* Send 2xx */ - send_RESPONSE(self, rOPTIONS, 200, "OK", tsk_false); + /* Send 2xx */ + send_RESPONSE(self, rOPTIONS, 200, "OK", tsk_false); - return 0; + return 0; } /* Any --> (i401/407 INVITE or UPDATE) --> Any */ int x0000_Any_2_Any_X_i401_407_Challenge(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - int ret; - - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - /* Alert the user. */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - if(TSIP_RESPONSE_IS_TO_INVITE(response) || TSIP_RESPONSE_IS_TO_UPDATE(response)){ - return send_INVITEorUPDATE(self, TSIP_RESPONSE_IS_TO_INVITE(response), tsk_false); - } - else if(TSIP_RESPONSE_IS_TO_BYE(response)){ - return send_BYE(self); - } - else{ - TSK_DEBUG_ERROR("Unexpected code called"); - return 0; - } + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + int ret; + + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + /* Alert the user. */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return ret; + } + + if(TSIP_RESPONSE_IS_TO_INVITE(response) || TSIP_RESPONSE_IS_TO_UPDATE(response)) { + return send_INVITEorUPDATE(self, TSIP_RESPONSE_IS_TO_INVITE(response), tsk_false); + } + else if(TSIP_RESPONSE_IS_TO_BYE(response)) { + return send_BYE(self); + } + else { + TSK_DEBUG_ERROR("Unexpected code called"); + return 0; + } } /* Any --> (i2xx INVITE or i2xx UPDATE) --> Any */ int x0000_Any_2_Any_X_i2xxINVITEorUPDATE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *r2xx = va_arg(*app, const tsip_response_t *); - int ret = 0; - - /* Update the dialog state */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xx))){ - return ret; - } - - /* session timers */ - if(self->stimers.timer.timeout){ - tsip_dialog_invite_stimers_handle(self, r2xx); - } - - /* Process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, r2xx))){ - send_BYE(self); - return ret; - } - - /* send ACK */ - if(TSIP_RESPONSE_IS_TO_INVITE(r2xx)){ - ret = send_ACK(self, r2xx); - } - - // starts ICE timers now that both parties received the "candidates" - if(tsip_dialog_invite_ice_is_enabled(self)){ - tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); - } - - return ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *r2xx = va_arg(*app, const tsip_response_t *); + int ret = 0; + + /* Update the dialog state */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xx))) { + return ret; + } + + /* session timers */ + if(self->stimers.timer.timeout) { + tsip_dialog_invite_stimers_handle(self, r2xx); + } + + /* Process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, r2xx))) { + send_BYE(self); + return ret; + } + + /* send ACK */ + if(TSIP_RESPONSE_IS_TO_INVITE(r2xx)) { + ret = send_ACK(self, r2xx); + } + + // starts ICE timers now that both parties received the "candidates" + if(tsip_dialog_invite_ice_is_enabled(self)) { + tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); + } + + return ret; } /* Any -> (oBYE) -> Trying */ int x0000_Any_2_Trying_X_oBYE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - int ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + int ret; - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); - /* send BYE */ - if((ret = send_BYE(self)) == 0){ + /* send BYE */ + if((ret = send_BYE(self)) == 0) { #if !TSIP_UNDER_APPLE // FIXME: hangs up on iOS (RTP transport runnable join never exits) - // stop session manager - if(self->msession_mgr && self->msession_mgr->started){ - tmedia_session_mgr_stop(self->msession_mgr); - } + // stop session manager + if(self->msession_mgr && self->msession_mgr->started) { + tmedia_session_mgr_stop(self->msession_mgr); + } #endif - } - return ret; + } + return ret; } /* Any -> (iBYE) -> Terminated */ int x0000_Any_2_Terminated_X_iBYE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rBYE = va_arg(*app, const tsip_request_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rBYE = va_arg(*app, const tsip_request_t *); - /* 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); - /* send 200 OK */ - return send_RESPONSE(self, rBYE, 200, "OK", tsk_false); + /* send 200 OK */ + return send_RESPONSE(self, rBYE, 200, "OK", tsk_false); } /* Any -> Shutdown -> Terminated */ int x0000_Any_2_Trying_X_shutdown(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - - /* schedule shutdow timeout */ - TSIP_DIALOG_INVITE_TIMER_SCHEDULE(shutdown); - - /* alert user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); - - if(TSIP_DIALOG(self)->state == tsip_established){ - return send_BYE(self); - } - else if(TSIP_DIALOG(self)->state == tsip_early){ - return send_CANCEL(self); - } - - return 0; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + + /* schedule shutdow timeout */ + TSIP_DIALOG_INVITE_TIMER_SCHEDULE(shutdown); + + /* alert user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + + if(TSIP_DIALOG(self)->state == tsip_established) { + return send_BYE(self); + } + else if(TSIP_DIALOG(self)->state == tsip_early) { + return send_CANCEL(self); + } + + return 0; } /* Any -> (i1xx) -> Any */ int x0000_Any_2_Any_X_i1xx(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *r1xx = va_arg(*app, const tsip_response_t *); - int ret = 0; - - /* Update the dialog state */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), r1xx))){ - return ret; - } - - /* RFC 3262 - 4 UAC Behavior - If a provisional response is received for an initial request, and - that response contains a Require header field containing the option - tag 100rel, the response is to be sent reliably. If the response is - a 100 (Trying) (as opposed to 101 to 199), this option tag MUST be - ignored, and the procedures below MUST NOT be used. - - Assuming the response is to be transmitted reliably, the UAC MUST - create a new request with method PRACK. This request is sent within - the dialog associated with the provisional response (indeed, the - provisional response may have created the dialog). PRACK requests - MAY contain bodies, which are interpreted according to their type and - disposition. - - Note that the PRACK is like any other non-INVITE request within a - dialog. In particular, a UAC SHOULD NOT retransmit the PRACK request - when it receives a retransmission of the provisional response being - acknowledged, although doing so does not create a protocol error. - - Additional information: We should only process the SDP from reliable responses (require:100rel) - but there was many problem with some clients sending SDP with this tag: tiscali, DTAG, samsung, ... - */ - if((TSIP_RESPONSE_CODE(r1xx) >= 101 && TSIP_RESPONSE_CODE(r1xx) <=199)){ - /* Process Remote offer */ - if(TSIP_MESSAGE_HAS_CONTENT(r1xx) && (ret = tsip_dialog_invite_process_ro(self, r1xx))){ - /* Send Error */ - return ret; - } - // don't send PRACK if 100rel is only inside "supported" header - if(tsip_message_required(r1xx, "100rel") && (ret = send_PRACK(self, r1xx))){ - return ret; - } - } - - /* QoS Reservation */ - if((self->qos.timer.id == TSK_INVALID_TIMER_ID) && tsip_message_required(r1xx, "precondition") && !tmedia_session_mgr_canresume(self->msession_mgr)){ - tsip_dialog_invite_qos_timer_schedule(self); - } - - /* alert the user */ - ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, - TSIP_RESPONSE_CODE(r1xx), TSIP_RESPONSE_PHRASE(r1xx), r1xx); - if(self->is_transf){ - ret = tsip_dialog_invite_notify_parent(self, r1xx); - } - - return ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *r1xx = va_arg(*app, const tsip_response_t *); + int ret = 0; + + /* Update the dialog state */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), r1xx))) { + return ret; + } + + /* RFC 3262 - 4 UAC Behavior + If a provisional response is received for an initial request, and + that response contains a Require header field containing the option + tag 100rel, the response is to be sent reliably. If the response is + a 100 (Trying) (as opposed to 101 to 199), this option tag MUST be + ignored, and the procedures below MUST NOT be used. + + Assuming the response is to be transmitted reliably, the UAC MUST + create a new request with method PRACK. This request is sent within + the dialog associated with the provisional response (indeed, the + provisional response may have created the dialog). PRACK requests + MAY contain bodies, which are interpreted according to their type and + disposition. + + Note that the PRACK is like any other non-INVITE request within a + dialog. In particular, a UAC SHOULD NOT retransmit the PRACK request + when it receives a retransmission of the provisional response being + acknowledged, although doing so does not create a protocol error. + + Additional information: We should only process the SDP from reliable responses (require:100rel) + but there was many problem with some clients sending SDP with this tag: tiscali, DTAG, samsung, ... + */ + if((TSIP_RESPONSE_CODE(r1xx) >= 101 && TSIP_RESPONSE_CODE(r1xx) <=199)) { + /* Process Remote offer */ + if(TSIP_MESSAGE_HAS_CONTENT(r1xx) && (ret = tsip_dialog_invite_process_ro(self, r1xx))) { + /* Send Error */ + return ret; + } + // don't send PRACK if 100rel is only inside "supported" header + if(tsip_message_required(r1xx, "100rel") && (ret = send_PRACK(self, r1xx))) { + return ret; + } + } + + /* QoS Reservation */ + if((self->qos.timer.id == TSK_INVALID_TIMER_ID) && tsip_message_required(r1xx, "precondition") && !tmedia_session_mgr_canresume(self->msession_mgr)) { + tsip_dialog_invite_qos_timer_schedule(self); + } + + /* alert the user */ + ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, + TSIP_RESPONSE_CODE(r1xx), TSIP_RESPONSE_PHRASE(r1xx), r1xx); + if(self->is_transf) { + ret = tsip_dialog_invite_notify_parent(self, r1xx); + } + + return ret; } /* Any -> (oINFO) -> Any */ int x0000_Any_2_Any_X_oINFO(va_list *app) { - tsip_dialog_invite_t *self; - const tsip_action_t* action; - tsip_request_t* rINFO; - - self = va_arg(*app, tsip_dialog_invite_t *); - va_arg(*app, const tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - if((rINFO = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))){ - int ret; - if(action){ - ret = tsip_dialog_apply_action(TSIP_MESSAGE(rINFO), action); - } - ret = tsip_dialog_request_send(TSIP_DIALOG(self), rINFO); - TSK_OBJECT_SAFE_FREE(rINFO); - return ret; - } - else{ - TSK_DEBUG_ERROR("Failed to create new INFO request"); - return -1; - } + tsip_dialog_invite_t *self; + const tsip_action_t* action; + tsip_request_t* rINFO; + + self = va_arg(*app, tsip_dialog_invite_t *); + va_arg(*app, const tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + if((rINFO = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))) { + int ret; + if(action) { + ret = tsip_dialog_apply_action(TSIP_MESSAGE(rINFO), action); + } + ret = tsip_dialog_request_send(TSIP_DIALOG(self), rINFO); + TSK_OBJECT_SAFE_FREE(rINFO); + return ret; + } + else { + TSK_DEBUG_ERROR("Failed to create new INFO request"); + return -1; + } } int x0000_Any_2_Any_X_iINFO(va_list *app) { - tsip_dialog_invite_t * self = va_arg(*app, tsip_dialog_invite_t *); - tsip_request_t* rINFO = (tsip_request_t*)va_arg(*app, const tsip_message_t *); - int ret = -1; - - if (rINFO){ - ret = send_RESPONSE(self, rINFO, 200, "Ok", tsk_false); - { - // int tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media); - if (self->msession_mgr && TSIP_MESSAGE_HAS_CONTENT(rINFO)){ - if (tsk_striequals("application/media_control+xml", TSIP_MESSAGE_CONTENT_TYPE(rINFO))){ /* rfc5168: XML Schema for Media Control */ - static uint32_t __ssrc_media_fake = 0; - static tmedia_type_t __tmedia_type_video = tmedia_video; // TODO: add bfcpvideo? - const char* content_ptr = (const char*)TSIP_MESSAGE_CONTENT_DATA(rINFO); - tsk_size_t content_size = (tsk_size_t)TSIP_MESSAGE_CONTENT_DATA_LENGTH(rINFO); - tsk_bool_t is_fir = tsk_false; - uint64_t sessionId = 0; + tsip_dialog_invite_t * self = va_arg(*app, tsip_dialog_invite_t *); + tsip_request_t* rINFO = (tsip_request_t*)va_arg(*app, const tsip_message_t *); + int ret = -1; + + if (rINFO) { + ret = send_RESPONSE(self, rINFO, 200, "Ok", tsk_false); + { + // int tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media); + if (self->msession_mgr && TSIP_MESSAGE_HAS_CONTENT(rINFO)) { + if (tsk_striequals("application/media_control+xml", TSIP_MESSAGE_CONTENT_TYPE(rINFO))) { /* rfc5168: XML Schema for Media Control */ + static uint32_t __ssrc_media_fake = 0; + static tmedia_type_t __tmedia_type_video = tmedia_video; // TODO: add bfcpvideo? + const char* content_ptr = (const char*)TSIP_MESSAGE_CONTENT_DATA(rINFO); + tsk_size_t content_size = (tsk_size_t)TSIP_MESSAGE_CONTENT_DATA_LENGTH(rINFO); + tsk_bool_t is_fir = tsk_false; + uint64_t sessionId = 0; #if HAVE_LIBXML2 - { - xmlDoc *pDoc; - xmlNode *pRootElement; - xmlXPathContext *pPathCtx; - xmlXPathObject *pPathObj; - static const xmlChar* __xpath_expr_picture_fast_update = (const xmlChar*)"/media_control/vc_primitive/to_encoder/picture_fast_update"; - static const xmlChar* __xpath_expr_stream_id = (const xmlChar*)"/media_control/vc_primitive/stream_id"; - - if (!(pDoc = xmlParseDoc(content_ptr))) { - TSK_DEBUG_ERROR("Failed to parse XML content [%s]", content_ptr); - return 0; - } - if (!(pRootElement = xmlDocGetRootElement(pDoc))) { - TSK_DEBUG_ERROR("Failed to get root element from XML content [%s]", content_ptr); - xmlFreeDoc(pDoc); - return 0; - } - if (!(pPathCtx = xmlXPathNewContext(pDoc))) { - TSK_DEBUG_ERROR("Failed to create path context from XML content [%s]", content_ptr); - xmlFreeDoc(pDoc); - return 0; - } - // picture_fast_update - if (!(pPathObj = xmlXPathEvalExpression(__xpath_expr_picture_fast_update, pPathCtx))) { - TSK_DEBUG_ERROR("Error: unable to evaluate xpath expression: %s", __xpath_expr_picture_fast_update); - xmlXPathFreeContext(pPathCtx); - xmlFreeDoc(pDoc); - return 0; - } - is_fir = (pPathObj->type == XPATH_NODESET && pPathObj->nodesetval->nodeNr > 0); - xmlXPathFreeObject(pPathObj); - // stream_id - if (!(pPathObj = xmlXPathEvalExpression(__xpath_expr_stream_id, pPathCtx))) { - TSK_DEBUG_ERROR("Error: unable to evaluate xpath expression: %s", __xpath_expr_stream_id); - xmlXPathFreeContext(pPathCtx); - xmlFreeDoc(pDoc); - } - else if (pPathObj->type == XPATH_NODESET && pPathObj->nodesetval->nodeNr > 0 && pPathObj->nodesetval->nodeTab[0]->children && pPathObj->nodesetval->nodeTab[0]->children->content) { - sessionId = tsk_atoi64((const char*)pPathObj->nodesetval->nodeTab[0]->children->content); - } - xmlXPathFreeObject(pPathObj); - - xmlXPathFreeContext(pPathCtx); - xmlFreeDoc(pDoc); - } + { + xmlDoc *pDoc; + xmlNode *pRootElement; + xmlXPathContext *pPathCtx; + xmlXPathObject *pPathObj; + static const xmlChar* __xpath_expr_picture_fast_update = (const xmlChar*)"/media_control/vc_primitive/to_encoder/picture_fast_update"; + static const xmlChar* __xpath_expr_stream_id = (const xmlChar*)"/media_control/vc_primitive/stream_id"; + + if (!(pDoc = xmlParseDoc(content_ptr))) { + TSK_DEBUG_ERROR("Failed to parse XML content [%s]", content_ptr); + return 0; + } + if (!(pRootElement = xmlDocGetRootElement(pDoc))) { + TSK_DEBUG_ERROR("Failed to get root element from XML content [%s]", content_ptr); + xmlFreeDoc(pDoc); + return 0; + } + if (!(pPathCtx = xmlXPathNewContext(pDoc))) { + TSK_DEBUG_ERROR("Failed to create path context from XML content [%s]", content_ptr); + xmlFreeDoc(pDoc); + return 0; + } + // picture_fast_update + if (!(pPathObj = xmlXPathEvalExpression(__xpath_expr_picture_fast_update, pPathCtx))) { + TSK_DEBUG_ERROR("Error: unable to evaluate xpath expression: %s", __xpath_expr_picture_fast_update); + xmlXPathFreeContext(pPathCtx); + xmlFreeDoc(pDoc); + return 0; + } + is_fir = (pPathObj->type == XPATH_NODESET && pPathObj->nodesetval->nodeNr > 0); + xmlXPathFreeObject(pPathObj); + // stream_id + if (!(pPathObj = xmlXPathEvalExpression(__xpath_expr_stream_id, pPathCtx))) { + TSK_DEBUG_ERROR("Error: unable to evaluate xpath expression: %s", __xpath_expr_stream_id); + xmlXPathFreeContext(pPathCtx); + xmlFreeDoc(pDoc); + } + else if (pPathObj->type == XPATH_NODESET && pPathObj->nodesetval->nodeNr > 0 && pPathObj->nodesetval->nodeTab[0]->children && pPathObj->nodesetval->nodeTab[0]->children->content) { + sessionId = tsk_atoi64((const char*)pPathObj->nodesetval->nodeTab[0]->children->content); + } + xmlXPathFreeObject(pPathObj); + + xmlXPathFreeContext(pPathCtx); + xmlFreeDoc(pDoc); + } #else - is_fir = (tsk_strcontains(content_ptr, content_size, "to_encoder") && tsk_strcontains(content_ptr, content_size, "picture_fast_update")); + is_fir = (tsk_strcontains(content_ptr, content_size, "to_encoder") && tsk_strcontains(content_ptr, content_size, "picture_fast_update")); #endif - if (is_fir) { - TSK_DEBUG_INFO("Incoming SIP INFO(picture_fast_update)"); - ret = sessionId - ? tmedia_session_mgr_recv_rtcp_event_2(self->msession_mgr, tmedia_rtcp_event_type_fir, sessionId) - : tmedia_session_mgr_recv_rtcp_event(self->msession_mgr, __tmedia_type_video, tmedia_rtcp_event_type_fir, __ssrc_media_fake); - } - else { - TSK_DEBUG_INFO("Incoming SIP INFO(unknown)"); - } - } - } - } - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request", rINFO); - } - - return ret; + if (is_fir) { + TSK_DEBUG_INFO("Incoming SIP INFO(picture_fast_update)"); + ret = sessionId + ? tmedia_session_mgr_recv_rtcp_event_2(self->msession_mgr, tmedia_rtcp_event_type_fir, sessionId) + : tmedia_session_mgr_recv_rtcp_event(self->msession_mgr, __tmedia_type_video, tmedia_rtcp_event_type_fir, __ssrc_media_fake); + } + else { + TSK_DEBUG_INFO("Incoming SIP INFO(unknown)"); + } + } + } + } + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request", rINFO); + } + + return ret; } int x9998_Any_2_Terminated_X_transportError(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 *); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Transport error", tsip_event_code_dialog_terminated); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Transport error", tsip_event_code_dialog_terminated); - return 0; + return 0; } int x9999_Any_2_Any_X_Error(va_list *app) { - return 0; + return 0; } @@ -1070,768 +1066,769 @@ int x9999_Any_2_Any_X_Error(va_list *app) int tsip_dialog_invite_msession_configure(tsip_dialog_invite_t *self) { - tmedia_srtp_mode_t srtp_mode; - tmedia_mode_t avpf_mode; - tsk_bool_t is_rtcweb_enabled; - tsk_bool_t is_webrtc2sip_mode_enabled; - - if(!self || !self->msession_mgr){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - is_webrtc2sip_mode_enabled = (TSIP_DIALOG_GET_STACK(self)->network.mode == tsip_stack_mode_webrtc2sip); - is_rtcweb_enabled = (((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.profile == tmedia_profile_rtcweb); - srtp_mode = is_rtcweb_enabled ? tmedia_srtp_mode_mandatory : ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.srtp_mode; - avpf_mode = is_rtcweb_enabled ? tmedia_mode_mandatory : ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.avpf_mode; - - // set callback functions - tmedia_session_mgr_set_onerror_cbfn(self->msession_mgr, self, tsip_dialog_invite_msession_onerror_cb); - tmedia_session_mgr_set_rfc5168_cbfn(self->msession_mgr, self, tsip_dialog_invite_msession_rfc5168_cb); - - // set params - return tmedia_session_mgr_set(self->msession_mgr, - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "srtp-mode", srtp_mode), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "avpf-mode", avpf_mode), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "webrtc2sip-mode-enabled", is_webrtc2sip_mode_enabled), // hack the media stack - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "rtcp-enabled", self->use_rtcp), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "rtcpmux-enabled", self->use_rtcpmux), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "codecs-supported", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.codecs), - - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "bypass-encoding", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.bypass_encoding), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "bypass-decoding", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.bypass_decoding), - - TMEDIA_SESSION_SET_INT32(tmedia_audio, "rtp-ssrc", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.rtp.ssrc.audio), - TMEDIA_SESSION_SET_INT32(tmedia_video, "rtp-ssrc", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.rtp.ssrc.video), - - TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-ca", TSIP_DIALOG_GET_STACK(self)->security.tls.ca), - TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-pbk", TSIP_DIALOG_GET_STACK(self)->security.tls.pbk), - TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-pvk", TSIP_DIALOG_GET_STACK(self)->security.tls.pvk), - TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "dtls-cert-verify", TSIP_DIALOG_GET_STACK(self)->security.tls.verify), - - TMEDIA_SESSION_SET_INT32(tmedia_video, "fps", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_fps), - TMEDIA_SESSION_SET_INT32(tmedia_video, "bandwidth-max-upload", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_bw_up), - TMEDIA_SESSION_SET_INT32(tmedia_video, "bandwidth-max-download", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_bw_down), - TMEDIA_SESSION_SET_INT32(tmedia_video, "pref-size", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_pref_size), - - tsk_null); + tmedia_srtp_mode_t srtp_mode; + tmedia_mode_t avpf_mode; + tsk_bool_t is_rtcweb_enabled; + tsk_bool_t is_webrtc2sip_mode_enabled; + + if(!self || !self->msession_mgr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + is_webrtc2sip_mode_enabled = (TSIP_DIALOG_GET_STACK(self)->network.mode == tsip_stack_mode_webrtc2sip); + is_rtcweb_enabled = (((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.profile == tmedia_profile_rtcweb); + srtp_mode = is_rtcweb_enabled ? tmedia_srtp_mode_mandatory : ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.srtp_mode; + avpf_mode = is_rtcweb_enabled ? tmedia_mode_mandatory : ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.avpf_mode; + + // set callback functions + tmedia_session_mgr_set_onerror_cbfn(self->msession_mgr, self, tsip_dialog_invite_msession_onerror_cb); + tmedia_session_mgr_set_rfc5168_cbfn(self->msession_mgr, self, tsip_dialog_invite_msession_rfc5168_cb); + + // set params + return tmedia_session_mgr_set(self->msession_mgr, + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "srtp-mode", srtp_mode), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "avpf-mode", avpf_mode), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "webrtc2sip-mode-enabled", is_webrtc2sip_mode_enabled), // hack the media stack + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "rtcp-enabled", self->use_rtcp), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "rtcpmux-enabled", self->use_rtcpmux), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "codecs-supported", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.codecs), + + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "bypass-encoding", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.bypass_encoding), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "bypass-decoding", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.bypass_decoding), + + TMEDIA_SESSION_SET_INT32(tmedia_audio, "rtp-ssrc", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.rtp.ssrc.audio), + TMEDIA_SESSION_SET_INT32(tmedia_video, "rtp-ssrc", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.rtp.ssrc.video), + + TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-ca", TSIP_DIALOG_GET_STACK(self)->security.tls.ca), + TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-pbk", TSIP_DIALOG_GET_STACK(self)->security.tls.pbk), + TMEDIA_SESSION_SET_STR(self->msession_mgr->type, "dtls-file-pvk", TSIP_DIALOG_GET_STACK(self)->security.tls.pvk), + TMEDIA_SESSION_SET_INT32(self->msession_mgr->type, "dtls-cert-verify", TSIP_DIALOG_GET_STACK(self)->security.tls.verify), + + TMEDIA_SESSION_SET_INT32(tmedia_video, "fps", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_fps), + TMEDIA_SESSION_SET_INT32(tmedia_video, "bandwidth-max-upload", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_bw_up), + TMEDIA_SESSION_SET_INT32(tmedia_video, "bandwidth-max-download", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_bw_down), + TMEDIA_SESSION_SET_INT32(tmedia_video, "pref-size", ((tsip_ssession_t*)TSIP_DIALOG(self)->ss)->media.video_pref_size), + + tsk_null); } int tsip_dialog_invite_msession_start(tsip_dialog_invite_t *self) { - if(!self || !self->msession_mgr){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(tsip_dialog_invite_ice_is_enabled(self) && !tsip_dialog_invite_ice_is_connected(self)){ - if(self->msession_mgr->type != self->ice.media_type){ - TSK_DEBUG_INFO("Media session type(%d)<>ICE media type(%d)", self->msession_mgr->type, self->ice.media_type); - // make sure to use the right media types - tsip_dialog_invite_ice_set_media_type(self, self->msession_mgr->type); - } - self->ice.start_smgr = tsk_true; - } - else{ - self->ice.start_smgr = tsk_false; - return tmedia_session_mgr_start(self->msession_mgr); - } - return 0; + if(!self || !self->msession_mgr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(tsip_dialog_invite_ice_is_enabled(self) && !tsip_dialog_invite_ice_is_connected(self)) { + if(self->msession_mgr->type != self->ice.media_type) { + TSK_DEBUG_INFO("Media session type(%d)<>ICE media type(%d)", self->msession_mgr->type, self->ice.media_type); + // make sure to use the right media types + tsip_dialog_invite_ice_set_media_type(self, self->msession_mgr->type); + } + self->ice.start_smgr = tsk_true; + } + else { + self->ice.start_smgr = tsk_false; + return tmedia_session_mgr_start(self->msession_mgr); + } + return 0; } // send INVITE/UPDATE request int send_INVITEorUPDATE(tsip_dialog_invite_t *self, tsk_bool_t is_INVITE, tsk_bool_t force_sdp) { - int ret = -1; - tsip_request_t *request = tsk_null; - tsk_bool_t bodiless = tsk_false; + int ret = -1; + tsip_request_t *request = tsk_null; + tsk_bool_t bodiless = tsk_false; #if BODILESS_INVITE - if(TSIP_DIALOG(self)->state == tsip_initial){ - bodiless = tsk_true; - } + if(TSIP_DIALOG(self)->state == tsip_initial) { + bodiless = tsk_true; + } #endif - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - if((request = tsip_dialog_request_new(TSIP_DIALOG(self), is_INVITE ? "INVITE" : "UPDATE"))){ - /* apply action params to the request (will add a content if the action contains one) */ - if(TSIP_DIALOG(self)->curr_action){ - tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); - } - - if(!bodiless){ - /* add our payload if current action does not have one */ - if((force_sdp || is_INVITE) || ((self->msession_mgr && self->msession_mgr->state_changed) || (TSIP_DIALOG(self)->state == tsip_initial))){ - if(!TSIP_DIALOG(self)->curr_action || !TSIP_DIALOG(self)->curr_action->payload){ - const tsdp_message_t* sdp_lo; - char* sdp; - if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))){ - tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); - if(tsip_dialog_invite_ice_is_enabled(self)){ - ret = tsip_dialog_invite_ice_process_lo(self, sdp_lo); - } - TSK_FREE(sdp); - } - } - } - } - - /* Session timers */ - if(self->stimers.timer.timeout){ - if(self->required.timer){ - tsip_message_add_headers(request, - TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, !self->stimers.is_refresher), - TSIP_HEADER_REQUIRE_VA_ARGS("timer"), - tsk_null - ); - } - else if(self->supported.timer){ - tsip_message_add_headers(request, - TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, !self->stimers.is_refresher), - TSIP_HEADER_SUPPORTED_VA_ARGS("timer"), - tsk_null - ); - } - - } - - if(self->stimers.minse){ - tsip_message_add_headers(request, - TSIP_HEADER_MIN_SE_VA_ARGS(self->stimers.minse), - tsk_null - ); - } - - /* 100rel */ - if(self->required._100rel){ - tsip_message_add_headers(request, - TSIP_HEADER_REQUIRE_VA_ARGS("100rel"), - tsk_null - ); - } - else if(self->supported._100rel){ - tsip_message_add_headers(request, - TSIP_HEADER_SUPPORTED_VA_ARGS("100rel"), - tsk_null - ); - } - - /* QoS */ - if(self->required.precondition){ - tsip_message_add_headers(request, - TSIP_HEADER_REQUIRE_VA_ARGS("precondition"), - tsk_null - ); - } - else if(self->supported.precondition){ - tsip_message_add_headers(request, - TSIP_HEADER_SUPPORTED_VA_ARGS("precondition"), - tsk_null - ); - } - - - /* Always added headers */ - // Explicit Communication Transfer (3GPP TS 24.629) - /*tsip_message_add_headers(request, - TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub,replaces"), - tsk_null - );*/ - - /* send the request */ - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - if(ret == 0){ - /* update last INVITE */ - TSK_OBJECT_SAFE_FREE(self->last_oInvite); - self->last_oInvite = request; - } - else{ - TSK_OBJECT_SAFE_FREE(request); - } - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + if((request = tsip_dialog_request_new(TSIP_DIALOG(self), is_INVITE ? "INVITE" : "UPDATE"))) { + /* apply action params to the request (will add a content if the action contains one) */ + if(TSIP_DIALOG(self)->curr_action) { + tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); + } + + if(!bodiless) { + /* add our payload if current action does not have one */ + if((force_sdp || is_INVITE) || ((self->msession_mgr && self->msession_mgr->state_changed) || (TSIP_DIALOG(self)->state == tsip_initial))) { + if(!TSIP_DIALOG(self)->curr_action || !TSIP_DIALOG(self)->curr_action->payload) { + const tsdp_message_t* sdp_lo; + char* sdp; + if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))) { + tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); + if(tsip_dialog_invite_ice_is_enabled(self)) { + ret = tsip_dialog_invite_ice_process_lo(self, sdp_lo); + } + TSK_FREE(sdp); + } + } + } + } + + /* Session timers */ + if(self->stimers.timer.timeout) { + if(self->required.timer) { + tsip_message_add_headers(request, + TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, !self->stimers.is_refresher), + TSIP_HEADER_REQUIRE_VA_ARGS("timer"), + tsk_null + ); + } + else if(self->supported.timer) { + tsip_message_add_headers(request, + TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, !self->stimers.is_refresher), + TSIP_HEADER_SUPPORTED_VA_ARGS("timer"), + tsk_null + ); + } + + } + + if(self->stimers.minse) { + tsip_message_add_headers(request, + TSIP_HEADER_MIN_SE_VA_ARGS(self->stimers.minse), + tsk_null + ); + } + + /* 100rel */ + if(self->required._100rel) { + tsip_message_add_headers(request, + TSIP_HEADER_REQUIRE_VA_ARGS("100rel"), + tsk_null + ); + } + else if(self->supported._100rel) { + tsip_message_add_headers(request, + TSIP_HEADER_SUPPORTED_VA_ARGS("100rel"), + tsk_null + ); + } + + /* QoS */ + if(self->required.precondition) { + tsip_message_add_headers(request, + TSIP_HEADER_REQUIRE_VA_ARGS("precondition"), + tsk_null + ); + } + else if(self->supported.precondition) { + tsip_message_add_headers(request, + TSIP_HEADER_SUPPORTED_VA_ARGS("precondition"), + tsk_null + ); + } + + + /* Always added headers */ + // Explicit Communication Transfer (3GPP TS 24.629) + /*tsip_message_add_headers(request, + TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub,replaces"), + tsk_null + );*/ + + /* send the request */ + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + if(ret == 0) { + /* update last INVITE */ + TSK_OBJECT_SAFE_FREE(self->last_oInvite); + self->last_oInvite = request; + } + else { + TSK_OBJECT_SAFE_FREE(request); + } + } bail: - return ret; + return ret; } // Send PRACK int send_PRACK(tsip_dialog_invite_t *self, const tsip_response_t* r1xx) { - // "Require: 100rel\r\n" should be checked by the caller of this function - int ret = -1; - tsip_request_t *request = tsk_null; - const tsip_header_RSeq_t* RSeq; - - if(!self || !r1xx || !r1xx->CSeq){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - - /* RFC 3262 - 4 UAC Behavior - The UAC MUST maintain a sequence number that indicates the most recently - received in-order reliable provisional response for the initial request. - */ - if((RSeq = (const tsip_header_RSeq_t*)tsip_message_get_header(r1xx, tsip_htype_RSeq))){ - - /* RFC 3262 - 4 UAC Behavior - If the UAC receives another reliable provisional - response to the same request, and its RSeq value is not one higher - than the value of the sequence number, that response MUST NOT be - acknowledged with a PRACK, and MUST NOT be processed further by the - UAC. An implementation MAY discard the response, or MAY cache the - response in the hopes of receiving the missing responses. - */ - if(self->rseq && (RSeq->seq <= self->rseq)){ - TSK_DEBUG_WARN("1xx.RSeq value is not one higher than lastINVITE.RSeq."); - ret = 0; /* Not error */ - goto bail; - } - self->rseq = RSeq->seq; - } - - /* RFC 3262 - 4 UAC Behavior - Assuming the response is to be transmitted reliably, the UAC MUST - create a new request with method PRACK. - */ - if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "PRACK"))){ - goto bail; - } - - /* RFC 3262 - 7.2 RAck - The first number is the value from the RSeq header in the provisional - response that is being acknowledged. The next number, and the - method, are copied from the CSeq in the response that is being - acknowledged. The method name in the RAck header is case sensitive. - */ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_RACK_VA_ARGS(self->rseq, r1xx->CSeq->seq, r1xx->CSeq->method)); - //TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Test", "value")); - - /* Initial INVITE was a bodiless request and 100rel is supported (I'm Alice) - 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->is_client && (self->last_oInvite && !TSIP_MESSAGE_HAS_CONTENT(self->last_oInvite))){ - const tsdp_message_t* sdp_lo; - char* sdp; - if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))){ - tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); - TSK_FREE(sdp); - } - } - - // Send request - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - + // "Require: 100rel\r\n" should be checked by the caller of this function + int ret = -1; + tsip_request_t *request = tsk_null; + const tsip_header_RSeq_t* RSeq; + + if(!self || !r1xx || !r1xx->CSeq) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + + /* RFC 3262 - 4 UAC Behavior + The UAC MUST maintain a sequence number that indicates the most recently + received in-order reliable provisional response for the initial request. + */ + if((RSeq = (const tsip_header_RSeq_t*)tsip_message_get_header(r1xx, tsip_htype_RSeq))) { + + /* RFC 3262 - 4 UAC Behavior + If the UAC receives another reliable provisional + response to the same request, and its RSeq value is not one higher + than the value of the sequence number, that response MUST NOT be + acknowledged with a PRACK, and MUST NOT be processed further by the + UAC. An implementation MAY discard the response, or MAY cache the + response in the hopes of receiving the missing responses. + */ + if(self->rseq && (RSeq->seq <= self->rseq)) { + TSK_DEBUG_WARN("1xx.RSeq value is not one higher than lastINVITE.RSeq."); + ret = 0; /* Not error */ + goto bail; + } + self->rseq = RSeq->seq; + } + + /* RFC 3262 - 4 UAC Behavior + Assuming the response is to be transmitted reliably, the UAC MUST + create a new request with method PRACK. + */ + if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "PRACK"))) { + goto bail; + } + + /* RFC 3262 - 7.2 RAck + The first number is the value from the RSeq header in the provisional + response that is being acknowledged. The next number, and the + method, are copied from the CSeq in the response that is being + acknowledged. The method name in the RAck header is case sensitive. + */ + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_RACK_VA_ARGS(self->rseq, r1xx->CSeq->seq, r1xx->CSeq->method)); + //TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Test", "value")); + + /* Initial INVITE was a bodiless request and 100rel is supported (I'm Alice) + 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->is_client && (self->last_oInvite && !TSIP_MESSAGE_HAS_CONTENT(self->last_oInvite))) { + const tsdp_message_t* sdp_lo; + char* sdp; + if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))) { + tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); + TSK_FREE(sdp); + } + } + + // Send request + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + bail: - TSK_OBJECT_SAFE_FREE(request); - return ret; + TSK_OBJECT_SAFE_FREE(request); + return ret; } // Send CANCEL int send_CANCEL(tsip_dialog_invite_t *self) { - int ret = -1; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - /* RFC 3261 - 9 Canceling a Request - If the request being cancelled contains a Route header field, the - CANCEL request MUST include that Route header field's values. - ==> up to tsip_dialog_request_new() - */ - - /* RFC 3261 - 9 Canceling a Request - Once the CANCEL is constructed, the client SHOULD check whether it - has received any response (provisional or final) for the request - being cancelled (herein referred to as the "original request"). - - If no provisional response has been received, the CANCEL request MUST - NOT be sent; rather, the client MUST wait for the arrival of a - provisional response before sending the request. - ==> up to the caller to check that we are not in the initial state and the FSM - is in Trying state. - */ - - /* RFC 3261 - 9 Canceling a Request - The following procedures are used to construct a CANCEL request. The - Request-URI, Call-ID, To, the numeric part of CSeq, and From header - fields in the CANCEL request MUST be identical to those in the - request being cancelled, including tags. A CANCEL constructed by a - client MUST have only a single Via header field value matching the - top Via value in the request being cancelled. Using the same values - for these header fields allows the CANCEL to be matched with the - request it cancels (Section 9.2 indicates how such matching occurs). - However, the method part of the CSeq header field MUST have a value - of CANCEL. This allows it to be identified and processed as a - transaction in its own right (See Section 17) - */ - if(self->last_oInvite){ - /* to avoid concurrent access, take a reference to the request */ - tsip_request_t* last_oInvite = tsk_object_ref(self->last_oInvite); - tsip_request_t* cancel; - - if((cancel = tsip_request_create("CANCEL", last_oInvite->line.request.uri))){ - const tsk_list_item_t* item; - const tsip_header_t* header; - - tsip_message_add_headers(cancel, - TSIP_HEADER_CSEQ_VA_ARGS(last_oInvite->CSeq->seq, "CANCEL"), - TSIP_HEADER_MAX_FORWARDS_VA_ARGS(TSIP_HEADER_MAX_FORWARDS_DEFAULT), - TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), - tsk_null); - - cancel->Call_ID = tsk_object_ref(last_oInvite->Call_ID); - cancel->To = tsk_object_ref(last_oInvite->To); - cancel->From = tsk_object_ref(last_oInvite->From); - cancel->firstVia = tsk_object_ref(last_oInvite->firstVia); - cancel->sigcomp_id = tsk_strdup(TSIP_DIALOG_GET_SS(self)->sigcomp_id); - - // Copy Authorizations, Routes and Proxy-Auth - tsk_list_foreach(item, last_oInvite->headers){ - if(!(header = TSIP_HEADER(item->data))){ - continue; - } - - switch(header->type){ - case tsip_htype_Route: - case tsip_htype_Proxy_Authorization: - case tsip_htype_Authorization: - header = tsk_object_ref((void*)header); - if(!cancel->headers){ - cancel->headers = tsk_list_create(); - } - tsk_list_push_back_data(cancel->headers, (void**)&header); - break; - default: break; - } - } - - ret = tsip_dialog_add_session_headers(TSIP_DIALOG(self), cancel); - ret = tsip_dialog_request_send(TSIP_DIALOG(self), cancel); - TSK_OBJECT_SAFE_FREE(cancel); - } - else{ - TSK_DEBUG_ERROR("Failed to create CANCEL request"); - ret = -2; - } - - TSK_OBJECT_SAFE_FREE(last_oInvite); - return ret; - } - else{ - TSK_DEBUG_WARN("There is no INVITE request to cancel"); - return 0; - } + int ret = -1; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + /* RFC 3261 - 9 Canceling a Request + If the request being cancelled contains a Route header field, the + CANCEL request MUST include that Route header field's values. + ==> up to tsip_dialog_request_new() + */ + + /* RFC 3261 - 9 Canceling a Request + Once the CANCEL is constructed, the client SHOULD check whether it + has received any response (provisional or final) for the request + being cancelled (herein referred to as the "original request"). + + If no provisional response has been received, the CANCEL request MUST + NOT be sent; rather, the client MUST wait for the arrival of a + provisional response before sending the request. + ==> up to the caller to check that we are not in the initial state and the FSM + is in Trying state. + */ + + /* RFC 3261 - 9 Canceling a Request + The following procedures are used to construct a CANCEL request. The + Request-URI, Call-ID, To, the numeric part of CSeq, and From header + fields in the CANCEL request MUST be identical to those in the + request being cancelled, including tags. A CANCEL constructed by a + client MUST have only a single Via header field value matching the + top Via value in the request being cancelled. Using the same values + for these header fields allows the CANCEL to be matched with the + request it cancels (Section 9.2 indicates how such matching occurs). + However, the method part of the CSeq header field MUST have a value + of CANCEL. This allows it to be identified and processed as a + transaction in its own right (See Section 17) + */ + if(self->last_oInvite) { + /* to avoid concurrent access, take a reference to the request */ + tsip_request_t* last_oInvite = tsk_object_ref(self->last_oInvite); + tsip_request_t* cancel; + + if((cancel = tsip_request_create("CANCEL", last_oInvite->line.request.uri))) { + const tsk_list_item_t* item; + const tsip_header_t* header; + + tsip_message_add_headers(cancel, + TSIP_HEADER_CSEQ_VA_ARGS(last_oInvite->CSeq->seq, "CANCEL"), + TSIP_HEADER_MAX_FORWARDS_VA_ARGS(TSIP_HEADER_MAX_FORWARDS_DEFAULT), + TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), + tsk_null); + + cancel->Call_ID = tsk_object_ref(last_oInvite->Call_ID); + cancel->To = tsk_object_ref(last_oInvite->To); + cancel->From = tsk_object_ref(last_oInvite->From); + cancel->firstVia = tsk_object_ref(last_oInvite->firstVia); + cancel->sigcomp_id = tsk_strdup(TSIP_DIALOG_GET_SS(self)->sigcomp_id); + + // Copy Authorizations, Routes and Proxy-Auth + tsk_list_foreach(item, last_oInvite->headers) { + if(!(header = TSIP_HEADER(item->data))) { + continue; + } + + switch(header->type) { + case tsip_htype_Route: + case tsip_htype_Proxy_Authorization: + case tsip_htype_Authorization: + header = tsk_object_ref((void*)header); + if(!cancel->headers) { + cancel->headers = tsk_list_create(); + } + tsk_list_push_back_data(cancel->headers, (void**)&header); + break; + default: + break; + } + } + + ret = tsip_dialog_add_session_headers(TSIP_DIALOG(self), cancel); + ret = tsip_dialog_request_send(TSIP_DIALOG(self), cancel); + TSK_OBJECT_SAFE_FREE(cancel); + } + else { + TSK_DEBUG_ERROR("Failed to create CANCEL request"); + ret = -2; + } + + TSK_OBJECT_SAFE_FREE(last_oInvite); + return ret; + } + else { + TSK_DEBUG_WARN("There is no INVITE request to cancel"); + return 0; + } bail: - return ret; + return ret; } int tsip_dialog_invite_notify_parent(tsip_dialog_invite_t *self, const tsip_response_t* response) { - int ret = -1; - tsip_dialog_t* dlg_parent = tsip_dialog_layer_find_by_ssid(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG_GET_SS(self)->id_parent); - if(dlg_parent){ - tsip_action_t* action = tsip_action_create(tsip_atype_ect_lnotify, - TSIP_ACTION_SET_NULL()); - if(action){ - ret = tsip_dialog_fsm_act(dlg_parent, action->type, response, action); - TSK_OBJECT_SAFE_FREE(action); - } - else{ - TSK_DEBUG_ERROR("Failed to create action object"); - } - TSK_OBJECT_SAFE_FREE(dlg_parent); - } - else{ - TSK_DEBUG_ERROR("Failed to find parent with id = %llu", TSIP_DIALOG_GET_SS(self)->id_parent); - } - return ret; + int ret = -1; + tsip_dialog_t* dlg_parent = tsip_dialog_layer_find_by_ssid(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG_GET_SS(self)->id_parent); + if(dlg_parent) { + tsip_action_t* action = tsip_action_create(tsip_atype_ect_lnotify, + TSIP_ACTION_SET_NULL()); + if(action) { + ret = tsip_dialog_fsm_act(dlg_parent, action->type, response, action); + TSK_OBJECT_SAFE_FREE(action); + } + else { + TSK_DEBUG_ERROR("Failed to create action object"); + } + TSK_OBJECT_SAFE_FREE(dlg_parent); + } + else { + TSK_DEBUG_ERROR("Failed to find parent with id = %llu", TSIP_DIALOG_GET_SS(self)->id_parent); + } + return ret; } // Send BYE int send_BYE(tsip_dialog_invite_t *self) { - int ret = -1; - tsip_request_t *bye = tsk_null; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - /* RFC 3261 - 15.1.1 UAC Behavior - A BYE request is constructed as would any other request within a - dialog, as described in Section 12. - - Once the BYE is constructed, the UAC core creates a new non-INVITE - client transaction, and passes it the BYE request. The UAC MUST - consider the session terminated (and therefore stop sending or - listening for media) as soon as the BYE request is passed to the - client transaction. If the response for the BYE is a 481 - (Call/Transaction Does Not Exist) or a 408 (Request Timeout) or no - - response at all is received for the BYE (that is, a timeout is - returned by the client transaction), the UAC MUST consider the - session and the dialog terminated. - */ - if((bye = tsip_dialog_request_new(TSIP_DIALOG(self), "BYE"))){ - if(TSIP_DIALOG(self)->curr_action){ - tsip_dialog_apply_action(bye, TSIP_DIALOG(self)->curr_action); - } - ret = tsip_dialog_request_send(TSIP_DIALOG(self), bye); - TSK_OBJECT_SAFE_FREE(bye); - } + int ret = -1; + tsip_request_t *bye = tsk_null; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + /* RFC 3261 - 15.1.1 UAC Behavior + A BYE request is constructed as would any other request within a + dialog, as described in Section 12. + + Once the BYE is constructed, the UAC core creates a new non-INVITE + client transaction, and passes it the BYE request. The UAC MUST + consider the session terminated (and therefore stop sending or + listening for media) as soon as the BYE request is passed to the + client transaction. If the response for the BYE is a 481 + (Call/Transaction Does Not Exist) or a 408 (Request Timeout) or no + + response at all is received for the BYE (that is, a timeout is + returned by the client transaction), the UAC MUST consider the + session and the dialog terminated. + */ + if((bye = tsip_dialog_request_new(TSIP_DIALOG(self), "BYE"))) { + if(TSIP_DIALOG(self)->curr_action) { + tsip_dialog_apply_action(bye, TSIP_DIALOG(self)->curr_action); + } + ret = tsip_dialog_request_send(TSIP_DIALOG(self), bye); + TSK_OBJECT_SAFE_FREE(bye); + } bail: - return ret; + return ret; } // Send INFO int send_INFO(tsip_dialog_invite_t *self, const char* content_type, const void* content_ptr, tsk_size_t content_size) { - int ret = -1; - tsip_request_t *info = tsk_null; - - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - if ((info = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))) { - if (TSIP_DIALOG(self)->curr_action) { - ret = tsip_dialog_apply_action(info, TSIP_DIALOG(self)->curr_action); - if (ret) { - goto bail; - } - } - if (content_type && content_ptr && content_size) { - ret = tsip_message_add_content(info, content_type, content_ptr, content_size); - if (ret) { - goto bail; - } - } - ret = tsip_dialog_request_send(TSIP_DIALOG(self), info); - if (ret) { - goto bail; - } - } + int ret = -1; + tsip_request_t *info = tsk_null; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + if ((info = tsip_dialog_request_new(TSIP_DIALOG(self), "INFO"))) { + if (TSIP_DIALOG(self)->curr_action) { + ret = tsip_dialog_apply_action(info, TSIP_DIALOG(self)->curr_action); + if (ret) { + goto bail; + } + } + if (content_type && content_ptr && content_size) { + ret = tsip_message_add_content(info, content_type, content_ptr, content_size); + if (ret) { + goto bail; + } + } + ret = tsip_dialog_request_send(TSIP_DIALOG(self), info); + if (ret) { + goto bail; + } + } bail: - TSK_OBJECT_SAFE_FREE(info); - return ret; + TSK_OBJECT_SAFE_FREE(info); + return ret; } // Send ACK int send_ACK(tsip_dialog_invite_t *self, const tsip_response_t* r2xxINVITE) { - int ret = -1; - tsip_request_t *request = tsk_null; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "ACK"))){ - - /* The initial INVITE sent by us was a bodiless request and we don't support 100rel (We are Alice) - 1. Alice sends initial INVITE without offer - 2. Bob's offer is sent in the 2xx INVITE response - 3. Alice's answer is sent in the ACK request - */ - if(self->is_client && (self->last_oInvite && !TSIP_MESSAGE_HAS_CONTENT(self->last_oInvite))){ - const tsdp_message_t* sdp_lo; - char* sdp; - if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))){ - tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); - TSK_FREE(sdp); - } - - // Start media session if not done - if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)){ - /* Set MSRP Callback */ - if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp){ - tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); - } - // starts session manager - ret = tsip_dialog_invite_msession_start(self); - } - } - - /* RFC 3261 - 13.2.2.4 2xx Responses - The UAC core MUST generate an ACK request for each 2xx received from - the transaction layer. The header fields of the ACK are constructed - in the same way as for any request sent within a dialog (see Section - 12) with the exception of the CSeq and the header fields related to - authentication. The sequence number of the CSeq header field MUST be - the same as the INVITE being acknowledged, but the CSeq method MUST - be ACK. The ACK MUST contain the same credentials as the INVITE. If - the 2xx contains an offer (based on the rules above), the ACK MUST - carry an answer in its body. If the offer in the 2xx response is not - acceptable, the UAC core MUST generate a valid answer in the ACK and - then send a BYE immediately. - ==> Credentials will be added by tsip_dialog_request_new() because they are - associated to the dialog itself. - ==> It's up to us to add/update the CSeq number. - ==> ACK requests sent here will create new client transactions, which means that - they will have there own branches. This is not the case for ACK requests sent from - the transaction layer. - */ - request->CSeq->seq = r2xxINVITE->CSeq->seq; /* As the 2xx has the same CSeq than the INVITE */ - - /* RFC 3261 - 13.2.2.4 2xx Responses - Once the ACK has been constructed, the procedures of [4] are used to - determine the destination address, port and transport. However, the - request is passed to the transport layer directly for transmission, - rather than a client transaction. This is because the UAC core - handles retransmissions of the ACK, not the transaction layer. The - ACK MUST be passed to the client transport every time a - retransmission of the 2xx final response that triggered the ACK - arrives. - */ - if(TSIP_DIALOG_GET_STACK(self)->layer_transport){ - ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, request); - } - else{ - ret = -1; - TSK_DEBUG_ERROR("Not Transport layer associated to this stack"); - } - TSK_OBJECT_SAFE_FREE(request); - } + int ret = -1; + tsip_request_t *request = tsk_null; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "ACK"))) { + + /* The initial INVITE sent by us was a bodiless request and we don't support 100rel (We are Alice) + 1. Alice sends initial INVITE without offer + 2. Bob's offer is sent in the 2xx INVITE response + 3. Alice's answer is sent in the ACK request + */ + if(self->is_client && (self->last_oInvite && !TSIP_MESSAGE_HAS_CONTENT(self->last_oInvite))) { + const tsdp_message_t* sdp_lo; + char* sdp; + if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))) { + tsip_message_add_content(request, "application/sdp", sdp, tsk_strlen(sdp)); + TSK_FREE(sdp); + } + + // Start media session if not done + if(!self->msession_mgr->started && (self->msession_mgr->sdp.lo && self->msession_mgr->sdp.ro)) { + /* Set MSRP Callback */ + if((self->msession_mgr->type & tmedia_msrp) == tmedia_msrp) { + tmedia_session_mgr_set_msrp_cb(self->msession_mgr, TSIP_DIALOG_GET_SS(self)->userdata, TSIP_DIALOG_GET_SS(self)->media.msrp.callback); + } + // starts session manager + ret = tsip_dialog_invite_msession_start(self); + } + } + + /* RFC 3261 - 13.2.2.4 2xx Responses + The UAC core MUST generate an ACK request for each 2xx received from + the transaction layer. The header fields of the ACK are constructed + in the same way as for any request sent within a dialog (see Section + 12) with the exception of the CSeq and the header fields related to + authentication. The sequence number of the CSeq header field MUST be + the same as the INVITE being acknowledged, but the CSeq method MUST + be ACK. The ACK MUST contain the same credentials as the INVITE. If + the 2xx contains an offer (based on the rules above), the ACK MUST + carry an answer in its body. If the offer in the 2xx response is not + acceptable, the UAC core MUST generate a valid answer in the ACK and + then send a BYE immediately. + ==> Credentials will be added by tsip_dialog_request_new() because they are + associated to the dialog itself. + ==> It's up to us to add/update the CSeq number. + ==> ACK requests sent here will create new client transactions, which means that + they will have there own branches. This is not the case for ACK requests sent from + the transaction layer. + */ + request->CSeq->seq = r2xxINVITE->CSeq->seq; /* As the 2xx has the same CSeq than the INVITE */ + + /* RFC 3261 - 13.2.2.4 2xx Responses + Once the ACK has been constructed, the procedures of [4] are used to + determine the destination address, port and transport. However, the + request is passed to the transport layer directly for transmission, + rather than a client transaction. This is because the UAC core + handles retransmissions of the ACK, not the transaction layer. The + ACK MUST be passed to the client transport every time a + retransmission of the 2xx final response that triggered the ACK + arrives. + */ + if(TSIP_DIALOG_GET_STACK(self)->layer_transport) { + ret = tsip_transport_layer_send(TSIP_DIALOG_GET_STACK(self)->layer_transport, tsk_null, request); + } + else { + ret = -1; + TSK_DEBUG_ERROR("Not Transport layer associated to this stack"); + } + TSK_OBJECT_SAFE_FREE(request); + } bail: - return ret; + return ret; } // Send any response int send_RESPONSE(tsip_dialog_invite_t *self, const tsip_request_t* request, short code, const char* phrase, tsk_bool_t force_sdp) { - tsip_response_t *response; - int ret = -1; - - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))){ - if(TSIP_REQUEST_IS_INVITE(request) || TSIP_REQUEST_IS_UPDATE(request)){ - /* Session timers (for 2xx to INVITE or UPDATE) */ - if(self->required.timer){ - tsip_message_add_headers(response, - TSIP_HEADER_REQUIRE_VA_ARGS("timer"), - TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, tsk_striequals(self->stimers.refresher, "uas")), - tsk_null - ); - } - else if(self->supported.timer){ - tsip_message_add_headers(response, - TSIP_HEADER_SUPPORTED_VA_ARGS("timer"), - TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, tsk_striequals(self->stimers.refresher, "uas")), - tsk_null - ); - } - if(self->stimers.minse){ - tsip_message_add_headers(response, - TSIP_HEADER_MIN_SE_VA_ARGS(self->stimers.minse), - tsk_null - ); - } - if(code == 422){ - tsip_message_add_headers(response, - TSIP_HEADER_DUMMY_VA_ARGS("Reason", "SIP; cause=422; text=\"Session Interval Too Small\""), - tsk_null - ); - } - - /* 180 Ringing */ - /* 183 Session in Progress */ - if(code == 180 || code == 183){ - if(self->required._100rel){ - if(self->rseq == 0){ - self->rseq = TSK_ABS((rand() ^ rand()) + 1); - } - tsip_message_add_headers(response, - TSIP_HEADER_REQUIRE_VA_ARGS("100rel"), - TSIP_HEADER_RSEQ_VA_ARGS(self->rseq), - tsk_null - ); - TSK_OBJECT_SAFE_FREE(self->last_o1xxrel); - self->last_o1xxrel = tsk_object_ref(response); - - /* No-Initial reliable 1xx will use tsip_dialog_response_send() instead of this function - * ==> can reseset timeout value and make initial schedule */ - TSIP_DIALOG_TIMER_CANCEL(100rel); - self->timer100rel.timeout = tsip_timers_getA(); - TSIP_DIALOG_INVITE_TIMER_SCHEDULE(100rel); - } - } - - /* Precondition */ - if(code == 180 || code == 183){ - if(self->required.precondition){ - tsip_message_add_headers(response, - TSIP_HEADER_REQUIRE_VA_ARGS("precondition"), - tsk_null - ); - } - } - - - /* SDP content */ - if(self->msession_mgr && force_sdp){ - const tsdp_message_t* sdp_lo; - char* sdp = tsk_null; - if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))){ - ret = tsip_message_add_content(response, "application/sdp", sdp, tsk_strlen(sdp)); - if(tsip_dialog_invite_ice_is_enabled(self)){ - ret = tsip_dialog_invite_ice_process_lo(self, sdp_lo); - } - } - TSK_FREE(sdp); - } - - /* Add Allow header */ - tsip_message_add_headers(response, - TSIP_HEADER_DUMMY_VA_ARGS("Allow", TSIP_HEADER_ALLOW_DEFAULT), - tsk_null - ); - } - else if(TSIP_REQUEST_IS_REFER(request)){ - if(self->required.norefersub){ - tsip_message_add_headers(response, - TSIP_HEADER_REQUIRE_VA_ARGS("norefersub"), - tsk_null - ); - } - if(self->supported.norefersub){ - tsip_message_add_headers(response, - TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub"), - tsk_null - ); - } - } - - - ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - return ret; + tsip_response_t *response; + int ret = -1; + + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))) { + if(TSIP_REQUEST_IS_INVITE(request) || TSIP_REQUEST_IS_UPDATE(request)) { + /* Session timers (for 2xx to INVITE or UPDATE) */ + if(self->required.timer) { + tsip_message_add_headers(response, + TSIP_HEADER_REQUIRE_VA_ARGS("timer"), + TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, tsk_striequals(self->stimers.refresher, "uas")), + tsk_null + ); + } + else if(self->supported.timer) { + tsip_message_add_headers(response, + TSIP_HEADER_SUPPORTED_VA_ARGS("timer"), + TSIP_HEADER_SESSION_EXPIRES_VA_ARGS(self->stimers.timer.timeout, tsk_striequals(self->stimers.refresher, "uas")), + tsk_null + ); + } + if(self->stimers.minse) { + tsip_message_add_headers(response, + TSIP_HEADER_MIN_SE_VA_ARGS(self->stimers.minse), + tsk_null + ); + } + if(code == 422) { + tsip_message_add_headers(response, + TSIP_HEADER_DUMMY_VA_ARGS("Reason", "SIP; cause=422; text=\"Session Interval Too Small\""), + tsk_null + ); + } + + /* 180 Ringing */ + /* 183 Session in Progress */ + if(code == 180 || code == 183) { + if(self->required._100rel) { + if(self->rseq == 0) { + self->rseq = TSK_ABS((rand() ^ rand()) + 1); + } + tsip_message_add_headers(response, + TSIP_HEADER_REQUIRE_VA_ARGS("100rel"), + TSIP_HEADER_RSEQ_VA_ARGS(self->rseq), + tsk_null + ); + TSK_OBJECT_SAFE_FREE(self->last_o1xxrel); + self->last_o1xxrel = tsk_object_ref(response); + + /* No-Initial reliable 1xx will use tsip_dialog_response_send() instead of this function + * ==> can reseset timeout value and make initial schedule */ + TSIP_DIALOG_TIMER_CANCEL(100rel); + self->timer100rel.timeout = tsip_timers_getA(); + TSIP_DIALOG_INVITE_TIMER_SCHEDULE(100rel); + } + } + + /* Precondition */ + if(code == 180 || code == 183) { + if(self->required.precondition) { + tsip_message_add_headers(response, + TSIP_HEADER_REQUIRE_VA_ARGS("precondition"), + tsk_null + ); + } + } + + + /* SDP content */ + if(self->msession_mgr && force_sdp) { + const tsdp_message_t* sdp_lo; + char* sdp = tsk_null; + if((sdp_lo = tmedia_session_mgr_get_lo(self->msession_mgr)) && (sdp = tsdp_message_tostring(sdp_lo))) { + ret = tsip_message_add_content(response, "application/sdp", sdp, tsk_strlen(sdp)); + if(tsip_dialog_invite_ice_is_enabled(self)) { + ret = tsip_dialog_invite_ice_process_lo(self, sdp_lo); + } + } + TSK_FREE(sdp); + } + + /* Add Allow header */ + tsip_message_add_headers(response, + TSIP_HEADER_DUMMY_VA_ARGS("Allow", TSIP_HEADER_ALLOW_DEFAULT), + tsk_null + ); + } + else if(TSIP_REQUEST_IS_REFER(request)) { + if(self->required.norefersub) { + tsip_message_add_headers(response, + TSIP_HEADER_REQUIRE_VA_ARGS("norefersub"), + tsk_null + ); + } + if(self->supported.norefersub) { + tsip_message_add_headers(response, + TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub"), + tsk_null + ); + } + } + + + ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + return ret; } // Send error response int send_ERROR(tsip_dialog_invite_t* self, const tsip_request_t* request, short code, const char* phrase, const char* reason) { - tsip_response_t *response; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))){ - tsip_message_add_headers(response, - TSIP_HEADER_DUMMY_VA_ARGS("Reason", reason), - tsk_null - ); - - tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - else{ - TSK_DEBUG_ERROR("Failed to create new message"); - } - return 0; + tsip_response_t *response; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))) { + tsip_message_add_headers(response, + TSIP_HEADER_DUMMY_VA_ARGS("Reason", reason), + tsk_null + ); + + tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + else { + TSK_DEBUG_ERROR("Failed to create new message"); + } + return 0; } // FSM callback to signal that the dialog is in the terminated state int tsip_dialog_invite_OnTerminated(tsip_dialog_invite_t *self) { - TSK_DEBUG_INFO("=== INVITE Dialog terminated ==="); - - /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed ) - worth nothing to do it here in order to cancel in-dialog request (such as INFO, REFER...) - */ - tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - - /* stop session manager */ - if(self->msession_mgr && self->msession_mgr->started){ - tmedia_session_mgr_stop(self->msession_mgr); - } - // because of C# and Java garbage collectors, the ICE context could - // be destroyed (then stoppped) very late - if(self->ice.ctx_audio){ - tnet_ice_ctx_stop(self->ice.ctx_audio); - } - if(self->ice.ctx_video){ - tnet_ice_ctx_stop(self->ice.ctx_video); - } - - /* alert the user */ - TSIP_DIALOG_SIGNAL_2(self, tsip_event_code_dialog_terminated, - TSIP_DIALOG(self)->last_error.phrase ? TSIP_DIALOG(self)->last_error.phrase : "Call Terminated", - TSIP_DIALOG(self)->last_error.message); - - /* Remove from the dialog layer. */ - return tsip_dialog_remove(TSIP_DIALOG(self)); + TSK_DEBUG_INFO("=== INVITE Dialog terminated ==="); + + /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed ) + worth nothing to do it here in order to cancel in-dialog request (such as INFO, REFER...) + */ + tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); + + /* stop session manager */ + if(self->msession_mgr && self->msession_mgr->started) { + tmedia_session_mgr_stop(self->msession_mgr); + } + // because of C# and Java garbage collectors, the ICE context could + // be destroyed (then stoppped) very late + if(self->ice.ctx_audio) { + tnet_ice_ctx_stop(self->ice.ctx_audio); + } + if(self->ice.ctx_video) { + tnet_ice_ctx_stop(self->ice.ctx_video); + } + + /* alert the user */ + TSIP_DIALOG_SIGNAL_2(self, tsip_event_code_dialog_terminated, + TSIP_DIALOG(self)->last_error.phrase ? TSIP_DIALOG(self)->last_error.phrase : "Call Terminated", + TSIP_DIALOG(self)->last_error.message); + + /* Remove from the dialog layer. */ + return tsip_dialog_remove(TSIP_DIALOG(self)); } // callback function called when media session error occures asynchronously static int tsip_dialog_invite_msession_onerror_cb(const void* usrdata, const struct tmedia_session_s* session, const char* reason, tsk_bool_t is_fatal) { - tsip_dialog_t *self = (tsip_dialog_t*)usrdata; - - if(self && is_fatal){ - char* str = tsk_null; - tsip_action_t* action; - tsk_sprintf(&str, "SIP; cause=488; text=\"%s\"", (reason ? reason : "Internal error")); - action = tsip_action_create(tsip_atype_hangup, - TSIP_ACTION_SET_HEADER("Reason", str), - TSIP_ACTION_SET_NULL()); - TSK_FREE(str); - - tsip_dialog_hangup(self, action); - TSK_OBJECT_SAFE_FREE(action); - } - - return 0; + tsip_dialog_t *self = (tsip_dialog_t*)usrdata; + + if(self && is_fatal) { + char* str = tsk_null; + tsip_action_t* action; + tsk_sprintf(&str, "SIP; cause=488; text=\"%s\"", (reason ? reason : "Internal error")); + action = tsip_action_create(tsip_atype_hangup, + TSIP_ACTION_SET_HEADER("Reason", str), + TSIP_ACTION_SET_NULL()); + TSK_FREE(str); + + tsip_dialog_hangup(self, action); + TSK_OBJECT_SAFE_FREE(action); + } + + return 0; } // callback function called when media session events (related to rfc5168) occures asynchronously static int tsip_dialog_invite_msession_rfc5168_cb(const void* usrdata, const struct tmedia_session_s* session, const char* reason, enum tmedia_session_rfc5168_cmd_e command) { - tsip_dialog_invite_t *self = (tsip_dialog_invite_t*)usrdata; - - if (self) { - if (command == tmedia_session_rfc5168_cmd_picture_fast_update) { - uint64_t now = tsk_time_now(); - if ((now - self->last_out_fastupdate_time) > TSIP_INFO_FASTUPDATE_OUT_INTERVAL_MIN) { - char* content_ptr = tsk_null; - static const char* __content_type = "application/media_control+xml"; - static const void* __content_format = - "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" - " <media_control>\r\n" - " <vc_primitive>\r\n" - " <to_encoder>\r\n" - " <picture_fast_update>\r\n" - " </picture_fast_update>\r\n" - " </to_encoder>\r\n" - " <stream_id>%llu</stream_id>\r\n" - " </vc_primitive>\r\n" - " </media_control>\r\n"; - TSK_DEBUG_INFO("Media session is asking the sigaling layer to send SIP INFO('picture_fast_update')"); - tsk_sprintf(&content_ptr, __content_format, session->id); - self->last_out_fastupdate_time = now; - return send_INFO(self, __content_type, content_ptr, tsk_strlen(content_ptr)); - } - else { - /* if too close don't update "last_fir_time" to "now" to be sure interval will increase */ - TSK_DEBUG_INFO("Outgoing SIP INFO ('picture_fast_update') requested but delay too close"); - } - } - } - return 0; + tsip_dialog_invite_t *self = (tsip_dialog_invite_t*)usrdata; + + if (self) { + if (command == tmedia_session_rfc5168_cmd_picture_fast_update) { + uint64_t now = tsk_time_now(); + if ((now - self->last_out_fastupdate_time) > TSIP_INFO_FASTUPDATE_OUT_INTERVAL_MIN) { + char* content_ptr = tsk_null; + static const char* __content_type = "application/media_control+xml"; + static const void* __content_format = + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + " <media_control>\r\n" + " <vc_primitive>\r\n" + " <to_encoder>\r\n" + " <picture_fast_update>\r\n" + " </picture_fast_update>\r\n" + " </to_encoder>\r\n" + " <stream_id>%llu</stream_id>\r\n" + " </vc_primitive>\r\n" + " </media_control>\r\n"; + TSK_DEBUG_INFO("Media session is asking the sigaling layer to send SIP INFO('picture_fast_update')"); + tsk_sprintf(&content_ptr, __content_format, session->id); + self->last_out_fastupdate_time = now; + return send_INFO(self, __content_type, content_ptr, tsk_strlen(content_ptr)); + } + else { + /* if too close don't update "last_fir_time" to "now" to be sure interval will increase */ + TSK_DEBUG_INFO("Outgoing SIP INFO ('picture_fast_update') requested but delay too close"); + } + } + } + return 0; } @@ -1857,86 +1854,85 @@ static int tsip_dialog_invite_msession_rfc5168_cb(const void* usrdata, const str // static tsk_object_t* tsip_dialog_invite_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_invite_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); - const char* call_id = va_arg(*app, const char *); - - /* Initialize base class */ - tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_INVITE, call_id, ss, _fsm_state_Started, _fsm_state_Terminated); - - /* FSM */ - TSIP_DIALOG_GET_FSM(dialog)->debug = DEBUG_STATE_MACHINE; - tsk_fsm_set_callback_terminated(TSIP_DIALOG_GET_FSM(dialog), TSK_FSM_ONTERMINATED_F(tsip_dialog_invite_OnTerminated), (const void*)dialog); - - /* default values */ - dialog->supported._100rel = ((tsip_ssession_t*)ss)->media.enable_100rel; - dialog->supported.norefersub = tsk_true; - dialog->required.ice = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb); - dialog->supported.ice = (dialog->required.ice || ((tsip_ssession_t*)ss)->media.enable_ice); + tsip_dialog_invite_t *dialog = self; + if(dialog) { + tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + const char* call_id = va_arg(*app, const char *); + + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_INVITE, call_id, ss, _fsm_state_Started, _fsm_state_Terminated); + + /* FSM */ + TSIP_DIALOG_GET_FSM(dialog)->debug = DEBUG_STATE_MACHINE; + tsk_fsm_set_callback_terminated(TSIP_DIALOG_GET_FSM(dialog), TSK_FSM_ONTERMINATED_F(tsip_dialog_invite_OnTerminated), (const void*)dialog); + + /* default values */ + dialog->supported._100rel = ((tsip_ssession_t*)ss)->media.enable_100rel; + dialog->supported.norefersub = tsk_true; + dialog->required.ice = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb); + dialog->supported.ice = (dialog->required.ice || ((tsip_ssession_t*)ss)->media.enable_ice); #if 0 /* This was a patch for chrome but no longer needed when using version 23.0.1271.64 or later */ - dialog->ice.is_jingle = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb); + dialog->ice.is_jingle = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb); #else - dialog->ice.is_jingle = tsk_false; + dialog->ice.is_jingle = tsk_false; #endif - dialog->ice.last_sdp_ro_ver = -1; - dialog->use_rtcp = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb) ? tsk_true : ((tsip_ssession_t*)ss)->media.enable_rtcp; - dialog->use_rtcpmux = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb) ? tsk_true : ((tsip_ssession_t*)ss)->media.enable_rtcpmux; - - dialog->ice.last_action_id = tsk_fsm_state_none; - dialog->refersub = tsk_true; - // ... do the same for preconditions, replaces, .... - - /* Initialize the class itself */ - tsip_dialog_invite_init(self); - } - return self; + dialog->ice.last_sdp_ro_ver = -1; + dialog->use_rtcp = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb) ? tsk_true : ((tsip_ssession_t*)ss)->media.enable_rtcp; + dialog->use_rtcpmux = (((tsip_ssession_t*)ss)->media.profile == tmedia_profile_rtcweb) ? tsk_true : ((tsip_ssession_t*)ss)->media.enable_rtcpmux; + + dialog->ice.last_action_id = tsk_fsm_state_none; + dialog->refersub = tsk_true; + // ... do the same for preconditions, replaces, .... + + /* Initialize the class itself */ + tsip_dialog_invite_init(self); + } + return self; } static tsk_object_t* tsip_dialog_invite_dtor(tsk_object_t * _self) -{ - tsip_dialog_invite_t *self = _self; - if(self){ - // Cancel all timers - tsip_dialog_invite_stimers_cancel(self); - tsip_dialog_invite_qos_timer_cancel(self); - TSIP_DIALOG_TIMER_CANCEL(shutdown); - TSIP_DIALOG_TIMER_CANCEL(100rel); - - // DeInitialize base class - tsip_dialog_deinit(TSIP_DIALOG(self)); - - // DeInitialize self - TSK_OBJECT_SAFE_FREE(self->ss_transf); - TSK_OBJECT_SAFE_FREE(self->msession_mgr); - - TSK_OBJECT_SAFE_FREE(self->last_oInvite); - TSK_OBJECT_SAFE_FREE(self->last_iInvite); - TSK_OBJECT_SAFE_FREE(self->last_o1xxrel); - TSK_OBJECT_SAFE_FREE(self->last_iRefer); - TSK_FREE(self->stimers.refresher); - - TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); - TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); - TSK_OBJECT_SAFE_FREE(self->ice.last_action); - TSK_OBJECT_SAFE_FREE(self->ice.last_message); - //... - - TSK_DEBUG_INFO("*** INVITE Dialog destroyed ***"); - } - return self; +{ + tsip_dialog_invite_t *self = _self; + if(self) { + // Cancel all timers + tsip_dialog_invite_stimers_cancel(self); + tsip_dialog_invite_qos_timer_cancel(self); + TSIP_DIALOG_TIMER_CANCEL(shutdown); + TSIP_DIALOG_TIMER_CANCEL(100rel); + + // DeInitialize base class + tsip_dialog_deinit(TSIP_DIALOG(self)); + + // DeInitialize self + TSK_OBJECT_SAFE_FREE(self->ss_transf); + TSK_OBJECT_SAFE_FREE(self->msession_mgr); + + TSK_OBJECT_SAFE_FREE(self->last_oInvite); + TSK_OBJECT_SAFE_FREE(self->last_iInvite); + TSK_OBJECT_SAFE_FREE(self->last_o1xxrel); + TSK_OBJECT_SAFE_FREE(self->last_iRefer); + TSK_FREE(self->stimers.refresher); + + TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); + TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); + TSK_OBJECT_SAFE_FREE(self->ice.last_action); + TSK_OBJECT_SAFE_FREE(self->ice.last_message); + //... + + TSK_DEBUG_INFO("*** INVITE Dialog destroyed ***"); + } + return self; } static int tsip_dialog_invite_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return tsip_dialog_cmp(obj1, obj2); + return tsip_dialog_cmp(obj1, obj2); } -static const tsk_object_def_t tsip_dialog_invite_def_s = -{ - sizeof(tsip_dialog_invite_t), - tsip_dialog_invite_ctor, - tsip_dialog_invite_dtor, - tsip_dialog_invite_cmp, +static const tsk_object_def_t tsip_dialog_invite_def_s = { + sizeof(tsip_dialog_invite_t), + tsip_dialog_invite_ctor, + tsip_dialog_invite_dtor, + tsip_dialog_invite_cmp, }; const tsk_object_def_t *tsip_dialog_invite_def_t = &tsip_dialog_invite_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.client.c b/tinySIP/src/dialogs/tsip_dialog_invite.client.c index c1be3c5..a831755 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.client.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.client.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. * @@ -68,45 +68,45 @@ static int c0000_Cancelling_2_Terminated_X_i300_to_699(va_list *app); /* 487 INV /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_is_resp2INVITE(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_INVITE(message); + return TSIP_RESPONSE_IS_TO_INVITE(message); } static tsk_bool_t _fsm_cond_is_resp2CANCEL(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_CANCEL(message); + return TSIP_RESPONSE_IS_TO_CANCEL(message); } /* Init FSM */ int tsip_dialog_invite_client_init(tsip_dialog_invite_t *self) { - return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (send INVITE) -> Outgoing - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_oINVITE, _fsm_state_Outgoing, c0000_Started_2_Outgoing_X_oINVITE, "c0000_Started_2_Outgoing_X_oINVITE"), - - /*======================= - * === Outgoing === - */ - // Outgoing -> (i2xx INVITE) -> Connected - TSK_FSM_ADD(_fsm_state_Outgoing, _fsm_action_i2xx, _fsm_cond_is_resp2INVITE, _fsm_state_Connected, c0000_Outgoing_2_Connected_X_i2xxINVITE, "c0000_Outgoing_2_Connected_X_i2xxINVITE"), - // Outgoing -> (iINVITE ) -> Outgoing - TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_iINVITE, _fsm_state_Outgoing, c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE, "c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE"), - // Outgoing -> (iUPDATE) -> Outgoing - TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_iUPDATE, _fsm_state_Outgoing, c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE, "c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE"), - // Outgoing -> (oCANCEL) -> Cancelling - TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_oCANCEL, _fsm_state_Cancelling, c0000_Outgoing_2_Cancelling_X_oCANCEL, "c0000_Outgoing_2_Cancelling_X_oCANCEL"), - // Cancelling -> (any response to cancel CANCEL) -> Cancelling - TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i300_to_i699, _fsm_cond_is_resp2CANCEL, _fsm_state_Terminated, tsk_null, "c0000_Cancelling_2_Terminated_X_i300_to_699"), - TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i2xx, _fsm_cond_is_resp2CANCEL, _fsm_state_Cancelling, tsk_null, "c0000_Cancelling_2_Cancelling_X_i2xx"), - // Cancelling -> (i300-699 INVITE) -> Terminated - TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITE, _fsm_state_Terminated, c0000_Cancelling_2_Terminated_X_i300_to_699, "c0000_Cancelling_2_Terminated_X_i300_to_699"), - // Outgoing -> (300-699 INVITE) -> Terminated - TSK_FSM_ADD(_fsm_state_Outgoing, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITE, _fsm_state_Terminated, c0000_Outgoing_2_Terminated_X_i300_to_i699INVITE, "c0000_Outgoing_2_Terminated_X_i300_to_i699INVITE"), - - TSK_FSM_ADD_NULL()); + return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (send INVITE) -> Outgoing + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_oINVITE, _fsm_state_Outgoing, c0000_Started_2_Outgoing_X_oINVITE, "c0000_Started_2_Outgoing_X_oINVITE"), + + /*======================= + * === Outgoing === + */ + // Outgoing -> (i2xx INVITE) -> Connected + TSK_FSM_ADD(_fsm_state_Outgoing, _fsm_action_i2xx, _fsm_cond_is_resp2INVITE, _fsm_state_Connected, c0000_Outgoing_2_Connected_X_i2xxINVITE, "c0000_Outgoing_2_Connected_X_i2xxINVITE"), + // Outgoing -> (iINVITE ) -> Outgoing + TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_iINVITE, _fsm_state_Outgoing, c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE, "c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE"), + // Outgoing -> (iUPDATE) -> Outgoing + TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_iUPDATE, _fsm_state_Outgoing, c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE, "c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE"), + // Outgoing -> (oCANCEL) -> Cancelling + TSK_FSM_ADD_ALWAYS(_fsm_state_Outgoing, _fsm_action_oCANCEL, _fsm_state_Cancelling, c0000_Outgoing_2_Cancelling_X_oCANCEL, "c0000_Outgoing_2_Cancelling_X_oCANCEL"), + // Cancelling -> (any response to cancel CANCEL) -> Cancelling + TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i300_to_i699, _fsm_cond_is_resp2CANCEL, _fsm_state_Terminated, tsk_null, "c0000_Cancelling_2_Terminated_X_i300_to_699"), + TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i2xx, _fsm_cond_is_resp2CANCEL, _fsm_state_Cancelling, tsk_null, "c0000_Cancelling_2_Cancelling_X_i2xx"), + // Cancelling -> (i300-699 INVITE) -> Terminated + TSK_FSM_ADD(_fsm_state_Cancelling, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITE, _fsm_state_Terminated, c0000_Cancelling_2_Terminated_X_i300_to_699, "c0000_Cancelling_2_Terminated_X_i300_to_699"), + // Outgoing -> (300-699 INVITE) -> Terminated + TSK_FSM_ADD(_fsm_state_Outgoing, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITE, _fsm_state_Terminated, c0000_Outgoing_2_Terminated_X_i300_to_i699INVITE, "c0000_Outgoing_2_Terminated_X_i300_to_i699INVITE"), + + TSK_FSM_ADD_NULL()); } //-------------------------------------------------------- @@ -117,215 +117,215 @@ int tsip_dialog_invite_client_init(tsip_dialog_invite_t *self) */ int c0000_Started_2_Outgoing_X_oINVITE(va_list *app) { - int ret; - 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 *); - - /* This is the first FSM transaction when you try to make an audio/video/msrp call */ - if(!self->msession_mgr){ - int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; - self->msession_mgr = tmedia_session_mgr_create(action ? action->media.type : tmedia_all, - TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), tsk_true); - if(TSIP_DIALOG_GET_STACK(self)->natt.ctx){ - ret = tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]); - } - - ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); - ret = tsip_dialog_invite_msession_configure(self); - } - - /* We are the client */ - self->is_client = tsk_true; - /* Whether it's a client dialog for call transfer */ - self->is_transf = (TSIP_DIALOG_GET_SS(self)->id_parent != TSIP_SSESSION_INVALID_ID); - - /* Get Media type from the action */ - TSIP_DIALOG_GET_SS(self)->media.type = action->media.type; - /* Appy media params received from the user */ - if(!TSK_LIST_IS_EMPTY(action->media.params)){ - tmedia_session_mgr_set_3(self->msession_mgr, action->media.params); - } - - /* RFC 4028 - 7.1. Generating an Initial Session Refresh Request - - A UAC MAY include a Session-Expires header field in an initial - session refresh request if it wants a session timer applied to the - session. The value of this header field indicates the session - interval desired by the UAC. If a Min-SE header is included in the - initial session refresh request, the value of the Session-Expires - MUST be greater than or equal to the value in Min-SE. - - The UAC MAY include the refresher parameter with value 'uac' if it - wants to perform the refreshes. However, it is RECOMMENDED that the - parameter be omitted so that it can be selected by the negotiation - mechanisms described below. - */ - if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout){ - self->stimers.timer.timeout = TSIP_DIALOG_GET_SS(self)->media.timers.timeout; - tsk_strupdate(&self->stimers.refresher, TSIP_DIALOG_GET_SS(self)->media.timers.refresher); - self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uac"); - self->supported.timer = tsk_true; - } - - /* QoS - * One Voice Profile - 5.4.1 SIP Precondition Considerations - * The UE shall use the Supported header, and not the Require header, to indicate the support of precondition in - * accordance with Section 5.1.3.1 of 3GPP TS 24.229. - */ - self->qos.type = TSIP_DIALOG_GET_SS(self)->media.qos.type; - self->qos.strength = TSIP_DIALOG_GET_SS(self)->media.qos.strength; - tmedia_session_mgr_set_qos(self->msession_mgr, self->qos.type, self->qos.strength); - self->supported.precondition = (self->qos.strength == tmedia_qos_strength_optional); - self->required.precondition = (self->qos.strength == tmedia_qos_strength_mandatory); - - /* send the request */ - ret = send_INVITE(self, tsk_false); - - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - - return ret; + int ret; + 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 *); + + /* This is the first FSM transaction when you try to make an audio/video/msrp call */ + if(!self->msession_mgr) { + int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; + self->msession_mgr = tmedia_session_mgr_create(action ? action->media.type : tmedia_all, + TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), tsk_true); + if(TSIP_DIALOG_GET_STACK(self)->natt.ctx) { + ret = tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]); + } + + ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); + ret = tsip_dialog_invite_msession_configure(self); + } + + /* We are the client */ + self->is_client = tsk_true; + /* Whether it's a client dialog for call transfer */ + self->is_transf = (TSIP_DIALOG_GET_SS(self)->id_parent != TSIP_SSESSION_INVALID_ID); + + /* Get Media type from the action */ + TSIP_DIALOG_GET_SS(self)->media.type = action->media.type; + /* Appy media params received from the user */ + if(!TSK_LIST_IS_EMPTY(action->media.params)) { + tmedia_session_mgr_set_3(self->msession_mgr, action->media.params); + } + + /* RFC 4028 - 7.1. Generating an Initial Session Refresh Request + + A UAC MAY include a Session-Expires header field in an initial + session refresh request if it wants a session timer applied to the + session. The value of this header field indicates the session + interval desired by the UAC. If a Min-SE header is included in the + initial session refresh request, the value of the Session-Expires + MUST be greater than or equal to the value in Min-SE. + + The UAC MAY include the refresher parameter with value 'uac' if it + wants to perform the refreshes. However, it is RECOMMENDED that the + parameter be omitted so that it can be selected by the negotiation + mechanisms described below. + */ + if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout) { + self->stimers.timer.timeout = TSIP_DIALOG_GET_SS(self)->media.timers.timeout; + tsk_strupdate(&self->stimers.refresher, TSIP_DIALOG_GET_SS(self)->media.timers.refresher); + self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uac"); + self->supported.timer = tsk_true; + } + + /* QoS + * One Voice Profile - 5.4.1 SIP Precondition Considerations + * The UE shall use the Supported header, and not the Require header, to indicate the support of precondition in + * accordance with Section 5.1.3.1 of 3GPP TS 24.229. + */ + self->qos.type = TSIP_DIALOG_GET_SS(self)->media.qos.type; + self->qos.strength = TSIP_DIALOG_GET_SS(self)->media.qos.strength; + tmedia_session_mgr_set_qos(self->msession_mgr, self->qos.type, self->qos.strength); + self->supported.precondition = (self->qos.strength == tmedia_qos_strength_optional); + self->required.precondition = (self->qos.strength == tmedia_qos_strength_mandatory); + + /* send the request */ + ret = send_INVITE(self, tsk_false); + + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + + return ret; } /* Outgoing -> (i2xx INVITE) -> Connected */ int c0000_Outgoing_2_Connected_X_i2xxINVITE(va_list *app) { - int ret; - - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *r2xxINVITE = va_arg(*app, const tsip_response_t *); - /* const tsip_action_t* action = */ va_arg(*app, const tsip_action_t *); - - /* Update the dialog state */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xxINVITE))){ - return ret; - } - - /* Process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, r2xxINVITE))){ - send_BYE(self); - return ret; - } - else{ - /* send ACK */ - ret = send_ACK(self, r2xxINVITE); - } - - /* Determine whether the remote party support UPDATE */ - self->support_update = tsip_message_allowed(r2xxINVITE, "UPDATE"); - - /* Session Timers */ - if(self->stimers.timer.timeout){ - tsip_dialog_invite_stimers_handle(self, r2xxINVITE); - } - - // starts ICE timers now that both parties received the "candidates" - if(tsip_dialog_invite_ice_is_enabled(self)){ - tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); - } - - /* Alert the user (session) */ - ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, - TSIP_RESPONSE_CODE(r2xxINVITE), TSIP_RESPONSE_PHRASE(r2xxINVITE), r2xxINVITE); - /* Alert the user (dialog) */ - ret = TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - - if(self->is_transf){ - ret = tsip_dialog_invite_notify_parent(self, r2xxINVITE); - self->is_transf = tsk_false;//final response -> no longer need to notify the parent - } - - /* MSRP File Transfer */ - /*if(TSIP_DIALOG(self)->curr_action && ((TSIP_DIALOG(self)->curr_action->media.type & tmedia_msrp) == tmedia_msrp)){ - // FIXME - tmedia_session_mgr_send_file(self->msession_mgr, "C:\\avatar.png", - TMEDIA_SESSION_SET_NULL()); - }*/ - - return ret; + int ret; + + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *r2xxINVITE = va_arg(*app, const tsip_response_t *); + /* const tsip_action_t* action = */ va_arg(*app, const tsip_action_t *); + + /* Update the dialog state */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), r2xxINVITE))) { + return ret; + } + + /* Process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, r2xxINVITE))) { + send_BYE(self); + return ret; + } + else { + /* send ACK */ + ret = send_ACK(self, r2xxINVITE); + } + + /* Determine whether the remote party support UPDATE */ + self->support_update = tsip_message_allowed(r2xxINVITE, "UPDATE"); + + /* Session Timers */ + if(self->stimers.timer.timeout) { + tsip_dialog_invite_stimers_handle(self, r2xxINVITE); + } + + // starts ICE timers now that both parties received the "candidates" + if(tsip_dialog_invite_ice_is_enabled(self)) { + tsip_dialog_invite_ice_timers_set(self, (self->required.ice ? -1 : TSIP_DIALOG_INVITE_ICE_CONNCHECK_TIMEOUT)); + } + + /* Alert the user (session) */ + ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, + TSIP_RESPONSE_CODE(r2xxINVITE), TSIP_RESPONSE_PHRASE(r2xxINVITE), r2xxINVITE); + /* Alert the user (dialog) */ + ret = TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + + if(self->is_transf) { + ret = tsip_dialog_invite_notify_parent(self, r2xxINVITE); + self->is_transf = tsk_false;//final response -> no longer need to notify the parent + } + + /* MSRP File Transfer */ + /*if(TSIP_DIALOG(self)->curr_action && ((TSIP_DIALOG(self)->curr_action->media.type & tmedia_msrp) == tmedia_msrp)){ + // FIXME + tmedia_session_mgr_send_file(self->msession_mgr, "C:\\avatar.png", + TMEDIA_SESSION_SET_NULL()); + }*/ + + return ret; } /* Outgoing -> (iINVITE or iINVITE) -> Outgoing */ int c0000_Outgoing_2_Outgoing_X_iINVITEorUPDATE(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_request_t *rINVITEorUPDATE = va_arg(*app, const tsip_request_t *); - tsk_bool_t force_sdp; - int ret = 0; - - /* process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, rINVITEorUPDATE))){ - /* Send error */ - return ret; - } - - /* Send 200 OK */ - // force SDP in 200 OK even if the request has the same SDP version - force_sdp = TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE); - ret = send_RESPONSE(self, rINVITEorUPDATE, 200, "OK", - (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); - - /* alert the user */ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, - tsip_event_code_dialog_request_incoming, "Incoming Request.", rINVITEorUPDATE); - - - return ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_request_t *rINVITEorUPDATE = va_arg(*app, const tsip_request_t *); + tsk_bool_t force_sdp; + int ret = 0; + + /* process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, rINVITEorUPDATE))) { + /* Send error */ + return ret; + } + + /* Send 200 OK */ + // force SDP in 200 OK even if the request has the same SDP version + force_sdp = TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE); + ret = send_RESPONSE(self, rINVITEorUPDATE, 200, "OK", + (self->msession_mgr && (force_sdp || self->msession_mgr->ro_changed || self->msession_mgr->state_changed))); + + /* alert the user */ + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_request, + tsip_event_code_dialog_request_incoming, "Incoming Request.", rINVITEorUPDATE); + + + return ret; } /* Outgoing -> (i300-i699 INVITE) -> Terminated */ int c0000_Outgoing_2_Terminated_X_i300_to_i699INVITE(va_list *app) { - int ret; - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - /* set last error (or info) */ - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), - TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - - /* alert the user */ - ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - if(self->is_transf){ - ret = tsip_dialog_invite_notify_parent(self, response); - self->is_transf = tsk_false;//final response -> no longer need to notify the parent - } - - return ret; + int ret; + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + /* set last error (or info) */ + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), + TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + + /* alert the user */ + ret = TSIP_DIALOG_INVITE_SIGNAL(self, tsip_ao_request, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + if(self->is_transf) { + ret = tsip_dialog_invite_notify_parent(self, response); + self->is_transf = tsk_false;//final response -> no longer need to notify the parent + } + + return ret; } /* Outgoing -> (oCANCEL ) -> Cancelling */ int c0000_Outgoing_2_Cancelling_X_oCANCEL(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 *); self->is_cancelling = tsk_true; - - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); - return send_CANCEL(self); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + + return send_CANCEL(self); } int c0000_Cancelling_2_Terminated_X_i300_to_699(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Request cancelled", TSIP_RESPONSE_CODE(response)); + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Request cancelled", TSIP_RESPONSE_CODE(response)); - return 0; + return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.ect.c b/tinySIP/src/dialogs/tsip_dialog_invite.ect.c index 8c21dd2..ec61f81 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.ect.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.ect.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. * @@ -73,71 +73,71 @@ static int x0400_iECTing_2_Connected_X_23456fNOTIFY(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_is_resp2REFER(tsip_dialog_invite_t* self, tsip_message_t* message) { - return TSIP_RESPONSE_IS_TO_REFER(message); + return TSIP_RESPONSE_IS_TO_REFER(message); } static tsk_bool_t _fsm_cond_is_1xxNOTIFY(tsip_dialog_invite_t* self, tsip_request_t* notify) { - short code = get_SipFragResponseCode(notify); - return (code >= 100 && code <= 199); + short code = get_SipFragResponseCode(notify); + return (code >= 100 && code <= 199); } static tsk_bool_t _fsm_cond_is_23456NOTIFY(tsip_dialog_invite_t* self, tsip_request_t* notify) { - short code = get_SipFragResponseCode(notify); - return (code >= 200 && code <= 699); + short code = get_SipFragResponseCode(notify); + return (code >= 200 && code <= 699); } static tsk_bool_t _fsm_cond_is_fREFER(tsip_dialog_invite_t* self, tsip_request_t* refer) { - const tsip_header_Refer_To_t* Refer_To = (const tsip_header_Refer_To_t*)tsip_message_get_header(refer, tsip_htype_Refer_To); - return (!Refer_To || !Refer_To->uri); + const tsip_header_Refer_To_t* Refer_To = (const tsip_header_Refer_To_t*)tsip_message_get_header(refer, tsip_htype_Refer_To); + return (!Refer_To || !Refer_To->uri); } static tsk_bool_t _fsm_cond_is_1xxfNOTIFY(tsip_dialog_invite_t* self, tsip_response_t* response) { - short code = TSIP_RESPONSE_CODE(response); - return (code >= 100 && code <= 199); + short code = TSIP_RESPONSE_CODE(response); + return (code >= 100 && code <= 199); } static tsk_bool_t _fsm_cond_is_23456fNOTIFY(tsip_dialog_invite_t* self, tsip_response_t* response) { - short code = TSIP_RESPONSE_CODE(response); - return (code >= 200 && code <= 699); + short code = TSIP_RESPONSE_CODE(response); + return (code >= 200 && code <= 699); } int tsip_dialog_invite_ect_init(tsip_dialog_invite_t *self) { - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Outgoing Transfer === - */ - // Connected -> (oREFER) -> oECTing - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oECT, _fsm_state_oECTing, x0400_Connected_2_oECTing_X_oECT, "x0400_Connected_2_oECTing_X_oECT"), - // oECTing -> (i2xx REFER) -> oECTing - TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_i2xx, _fsm_cond_is_resp2REFER, _fsm_state_oECTing, x0400_oECTing_2_oECTing_X_i2xx, "x0400_oECTing_2_oECTing_X_i2xx"), - // oECTing -> (i300-699 REFER) -> Connected - TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_i300_to_i699, _fsm_cond_is_resp2REFER, _fsm_state_Connected, x0400_oECTing_2_Connected_X_i3456, "x0400_ECTing_2_Connected_X_i36"), - // oECTing -> (iNotify 1xx sipfrag) -> oECTing - TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_iNOTIFY, _fsm_cond_is_1xxNOTIFY, _fsm_state_oECTing, x0400_oECTing_2_oECTing_X_iNOTIFY, "x0400_oECTing_2_oECTing_X_iNOTIFY"), - // oECTing -> (iNotify 23456 sipfrag) -> Connected - TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_iNOTIFY, _fsm_cond_is_23456NOTIFY, _fsm_state_Connected, x0400_oECTing_2_Connected_X_iNOTIFY, "x0400_oECTing_2_Connected_X_iNOTIFY"), - - /*======================= - * === Incoming Transfer === - */ - // Connected -> (iREFER invalid) -> Connected - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREFER, _fsm_cond_is_fREFER, _fsm_state_Connected, x0400_Connected_2_Connected_X_fREFER, "x0400_Connected_2_Connected_X_fREFER"), - // Connected -> (iREFER) -> iECTreq - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iREFER, _fsm_state_iECTreq, x0400_Connected_2_iECTreq_X_iREFER, "x0400_Connected_2_iECTreq_X_iREFER"), - // iECTreq -> (reject) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_iECTreq, _fsm_action_iECT_REJECT, _fsm_state_Connected, x0400_iECTreq_2_Connected_X_reject, "x0400_iECTreq_2_Connected_X_reject"), - // iECTreq -> (accept) -> iECTing - TSK_FSM_ADD_ALWAYS(_fsm_state_iECTreq, _fsm_action_iECT_ACCEPT, _fsm_state_iECTing, x0400_iECTreq_2_iECTing_X_accept, "x0400_iECTreq_2_iECTing_X_accept"), - // iECTing -> (1xx lnotify) -> iECTing - TSK_FSM_ADD(_fsm_state_iECTing, _fsm_action_iECT_lNOTIFY, _fsm_cond_is_1xxfNOTIFY, _fsm_state_iECTing, x0400_iECTing_2_iECTing_X_1xxfNOTIFY, "x0400_iECTing_2_iECTing_X_1xxfNOTIFY"), - // iECTing -> (23456 lnotify) -> Connected - TSK_FSM_ADD(_fsm_state_iECTing, _fsm_action_iECT_lNOTIFY, _fsm_cond_is_23456fNOTIFY, _fsm_state_Connected, x0400_iECTing_2_Connected_X_23456fNOTIFY, "x0400_iECTing_2_Connected_X_23456fNOTIFY"), - - TSK_FSM_ADD_NULL()); - - return 0; + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Outgoing Transfer === + */ + // Connected -> (oREFER) -> oECTing + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oECT, _fsm_state_oECTing, x0400_Connected_2_oECTing_X_oECT, "x0400_Connected_2_oECTing_X_oECT"), + // oECTing -> (i2xx REFER) -> oECTing + TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_i2xx, _fsm_cond_is_resp2REFER, _fsm_state_oECTing, x0400_oECTing_2_oECTing_X_i2xx, "x0400_oECTing_2_oECTing_X_i2xx"), + // oECTing -> (i300-699 REFER) -> Connected + TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_i300_to_i699, _fsm_cond_is_resp2REFER, _fsm_state_Connected, x0400_oECTing_2_Connected_X_i3456, "x0400_ECTing_2_Connected_X_i36"), + // oECTing -> (iNotify 1xx sipfrag) -> oECTing + TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_iNOTIFY, _fsm_cond_is_1xxNOTIFY, _fsm_state_oECTing, x0400_oECTing_2_oECTing_X_iNOTIFY, "x0400_oECTing_2_oECTing_X_iNOTIFY"), + // oECTing -> (iNotify 23456 sipfrag) -> Connected + TSK_FSM_ADD(_fsm_state_oECTing, _fsm_action_iNOTIFY, _fsm_cond_is_23456NOTIFY, _fsm_state_Connected, x0400_oECTing_2_Connected_X_iNOTIFY, "x0400_oECTing_2_Connected_X_iNOTIFY"), + + /*======================= + * === Incoming Transfer === + */ + // Connected -> (iREFER invalid) -> Connected + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREFER, _fsm_cond_is_fREFER, _fsm_state_Connected, x0400_Connected_2_Connected_X_fREFER, "x0400_Connected_2_Connected_X_fREFER"), + // Connected -> (iREFER) -> iECTreq + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_iREFER, _fsm_state_iECTreq, x0400_Connected_2_iECTreq_X_iREFER, "x0400_Connected_2_iECTreq_X_iREFER"), + // iECTreq -> (reject) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_iECTreq, _fsm_action_iECT_REJECT, _fsm_state_Connected, x0400_iECTreq_2_Connected_X_reject, "x0400_iECTreq_2_Connected_X_reject"), + // iECTreq -> (accept) -> iECTing + TSK_FSM_ADD_ALWAYS(_fsm_state_iECTreq, _fsm_action_iECT_ACCEPT, _fsm_state_iECTing, x0400_iECTreq_2_iECTing_X_accept, "x0400_iECTreq_2_iECTing_X_accept"), + // iECTing -> (1xx lnotify) -> iECTing + TSK_FSM_ADD(_fsm_state_iECTing, _fsm_action_iECT_lNOTIFY, _fsm_cond_is_1xxfNOTIFY, _fsm_state_iECTing, x0400_iECTing_2_iECTing_X_1xxfNOTIFY, "x0400_iECTing_2_iECTing_X_1xxfNOTIFY"), + // iECTing -> (23456 lnotify) -> Connected + TSK_FSM_ADD(_fsm_state_iECTing, _fsm_action_iECT_lNOTIFY, _fsm_cond_is_23456fNOTIFY, _fsm_state_Connected, x0400_iECTing_2_Connected_X_23456fNOTIFY, "x0400_iECTing_2_Connected_X_23456fNOTIFY"), + + TSK_FSM_ADD_NULL()); + + return 0; } @@ -148,235 +148,235 @@ int tsip_dialog_invite_ect_init(tsip_dialog_invite_t *self) // Connected -> (oREFER) -> oECTing static int x0400_Connected_2_oECTing_X_oECT(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_action_t* action; + int ret; + 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 *); - ret = send_REFER(self, action->ect.to); + ret = send_REFER(self, action->ect.to); - if(ret == 0){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_trying, - tsip_event_code_dialog_request_sent, "Call Transfer Initiated", tsk_null); - } - else; //Must never happen + if(ret == 0) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_trying, + tsip_event_code_dialog_request_sent, "Call Transfer Initiated", tsk_null); + } + else; //Must never happen - return ret; + return ret; } // ECTing -> (i2xx REFER) -> oECTing static int x0400_oECTing_2_oECTing_X_i2xx(va_list *app) { - tsip_dialog_invite_t *self; - const tsip_response_t* response; - const tsip_header_Refer_Sub_t* Refer_Sub; - - self = va_arg(*app, tsip_dialog_invite_t *); - response = va_arg(*app, const tsip_message_t *); - Refer_Sub = (const tsip_header_Refer_Sub_t*)tsip_message_get_header(response, tsip_htype_Refer_Sub); - if(Refer_Sub){ - self->refersub = Refer_Sub->sub; - } - if(tsip_message_required(response, "norefersub")){ - self->required.norefersub = tsk_true; - } - - return TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_accepted, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + tsip_dialog_invite_t *self; + const tsip_response_t* response; + const tsip_header_Refer_Sub_t* Refer_Sub; + + self = va_arg(*app, tsip_dialog_invite_t *); + response = va_arg(*app, const tsip_message_t *); + Refer_Sub = (const tsip_header_Refer_Sub_t*)tsip_message_get_header(response, tsip_htype_Refer_Sub); + if(Refer_Sub) { + self->refersub = Refer_Sub->sub; + } + if(tsip_message_required(response, "norefersub")) { + self->required.norefersub = tsk_true; + } + + return TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_accepted, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); } // oECTing -> (i300-699 REFER) -> Connected static int x0400_oECTing_2_Connected_X_i3456(va_list *app) { - tsip_dialog_invite_t *self; - const tsip_response_t* response; + tsip_dialog_invite_t *self; + const tsip_response_t* response; - self = va_arg(*app, tsip_dialog_invite_t *); - response = va_arg(*app, const tsip_message_t *); + self = va_arg(*app, tsip_dialog_invite_t *); + response = va_arg(*app, const tsip_message_t *); - return TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_failed, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + return TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_failed, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); } // oECTing -> (iNotify 1xx sipfrag) -> oECTing static int x0400_oECTing_2_oECTing_X_iNOTIFY(va_list *app) { - int ret = 0; - tsip_dialog_invite_t *self; - const tsip_request_t* notify; - tsip_response_t *sipfrag = tsk_null; + int ret = 0; + tsip_dialog_invite_t *self; + const tsip_request_t* notify; + tsip_response_t *sipfrag = tsk_null; - self = va_arg(*app, tsip_dialog_invite_t *); - notify = va_arg(*app, const tsip_message_t *); + self = va_arg(*app, tsip_dialog_invite_t *); + notify = va_arg(*app, const tsip_message_t *); - sipfrag = get_SipFragMessage(notify); - if(sipfrag){ - send_RESPONSE(self, notify, 200, "Ok", tsk_false); - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, - TSIP_RESPONSE_CODE(sipfrag), TSIP_RESPONSE_PHRASE(sipfrag), notify); - } + sipfrag = get_SipFragMessage(notify); + if(sipfrag) { + send_RESPONSE(self, notify, 200, "Ok", tsk_false); + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, + TSIP_RESPONSE_CODE(sipfrag), TSIP_RESPONSE_PHRASE(sipfrag), notify); + } - TSK_OBJECT_SAFE_FREE(sipfrag); + TSK_OBJECT_SAFE_FREE(sipfrag); - return ret; + return ret; } // oECTing -> (iNotify 23456 sipfrag) -> Connected static int x0400_oECTing_2_Connected_X_iNOTIFY(va_list *app) { - int ret = 0; - tsip_dialog_invite_t *self; - const tsip_request_t* notify; - tsip_response_t *sipfrag = tsk_null; + int ret = 0; + tsip_dialog_invite_t *self; + const tsip_request_t* notify; + tsip_response_t *sipfrag = tsk_null; - self = va_arg(*app, tsip_dialog_invite_t *); - notify = va_arg(*app, const tsip_message_t *); + self = va_arg(*app, tsip_dialog_invite_t *); + notify = va_arg(*app, const tsip_message_t *); - sipfrag = get_SipFragMessage(notify); - if(sipfrag){ - send_RESPONSE(self, notify, 200, "Ok", tsk_false); - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, - TSIP_RESPONSE_CODE(sipfrag), TSIP_RESPONSE_PHRASE(sipfrag), notify); - } + sipfrag = get_SipFragMessage(notify); + if(sipfrag) { + send_RESPONSE(self, notify, 200, "Ok", tsk_false); + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, + TSIP_RESPONSE_CODE(sipfrag), TSIP_RESPONSE_PHRASE(sipfrag), notify); + } - TSK_OBJECT_SAFE_FREE(sipfrag); + TSK_OBJECT_SAFE_FREE(sipfrag); - return ret; + return ret; } // Connected -> (iREFER) -> iECTreq static int x0400_Connected_2_iECTreq_X_iREFER(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_request_t* refer; - - self = va_arg(*app, tsip_dialog_invite_t *); - refer = va_arg(*app, const tsip_message_t *); - - TSK_OBJECT_SAFE_FREE(self->last_iRefer); - self->last_iRefer = tsk_object_ref((tsk_object_t*)refer); - - ret = send_RESPONSE(self, self->last_iRefer, 100, "Asking for Transfer", tsk_false); - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_requested, - tsip_event_code_dialog_request_incoming, "Incoming Request", self->last_iRefer); - - return ret; + int ret; + tsip_dialog_invite_t *self; + const tsip_request_t* refer; + + self = va_arg(*app, tsip_dialog_invite_t *); + refer = va_arg(*app, const tsip_message_t *); + + TSK_OBJECT_SAFE_FREE(self->last_iRefer); + self->last_iRefer = tsk_object_ref((tsk_object_t*)refer); + + ret = send_RESPONSE(self, self->last_iRefer, 100, "Asking for Transfer", tsk_false); + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_requested, + tsip_event_code_dialog_request_incoming, "Incoming Request", self->last_iRefer); + + return ret; } // iECTreq -> (reject) -> Connected static int x0400_iECTreq_2_Connected_X_reject(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_action_t* action; - short code; - const char* phrase; - char* reason = tsk_null; - - self = va_arg(*app, tsip_dialog_invite_t *); - va_arg(*app, const tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - // Send Reject - code = action->line_resp.code>=300 ? action->line_resp.code : 603; - phrase = action->line_resp.phrase ? action->line_resp.phrase : "Decline Transfer"; - tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); - ret = send_ERROR(self, self->last_iRefer, code, phrase, reason); - TSK_FREE(reason); - - return ret; + int ret; + tsip_dialog_invite_t *self; + const tsip_action_t* action; + short code; + const char* phrase; + char* reason = tsk_null; + + self = va_arg(*app, tsip_dialog_invite_t *); + va_arg(*app, const tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + // Send Reject + code = action->line_resp.code>=300 ? action->line_resp.code : 603; + phrase = action->line_resp.phrase ? action->line_resp.phrase : "Decline Transfer"; + tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); + ret = send_ERROR(self, self->last_iRefer, code, phrase, reason); + TSK_FREE(reason); + + return ret; } // iECTreq -> (accept) -> iECTing static int x0400_iECTreq_2_iECTing_X_accept(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_header_Refer_To_t* Refer_To; - 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 *); - - // Send 200 OK - ret = send_RESPONSE(self, self->last_iRefer, 200, "Transfering", tsk_false); - Refer_To = (const tsip_header_Refer_To_t*)tsip_message_get_header(self->last_iRefer, tsip_htype_Refer_To); // Not null: already checked - // Make call to the referToUri - TSK_OBJECT_SAFE_FREE(self->ss_transf); - self->ss_transf = tsip_ssession_create(TSIP_DIALOG_GET_STACK(self), - TSIP_SSESSION_SET_PARENT_ID(TSIP_DIALOG_GET_SS(self)->id), - TSIP_SSESSION_SET_NULL()); + int ret; + tsip_dialog_invite_t *self; + const tsip_header_Refer_To_t* Refer_To; + 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 *); + + // Send 200 OK + ret = send_RESPONSE(self, self->last_iRefer, 200, "Transfering", tsk_false); + Refer_To = (const tsip_header_Refer_To_t*)tsip_message_get_header(self->last_iRefer, tsip_htype_Refer_To); // Not null: already checked + // Make call to the referToUri + TSK_OBJECT_SAFE_FREE(self->ss_transf); + self->ss_transf = tsip_ssession_create(TSIP_DIALOG_GET_STACK(self), + TSIP_SSESSION_SET_PARENT_ID(TSIP_DIALOG_GET_SS(self)->id), + TSIP_SSESSION_SET_NULL()); #if TSIP_UNDER_WINDOWS // because of DirectShow Attach() - self->ss_transf->media.type = tmedia_audio; + self->ss_transf->media.type = tmedia_audio; #else - self->ss_transf->media.type = self->msession_mgr ? self->msession_mgr->type : tmedia_defaults_get_media_type(); + self->ss_transf->media.type = self->msession_mgr ? self->msession_mgr->type : tmedia_defaults_get_media_type(); #endif - self->ss_transf->owner = tsk_false;// not owned by the end-user -> will be destroyed as soon as the dialog dtor is called - - if(ret == 0){ - ret = tsip_invite_event_signal(tsip_i_ect_newcall, self->ss_transf, - tsip_event_code_dialog_request_outgoing, "ECTing", self->last_iRefer); - } - - ret = tsip_ssession_set(self->ss_transf, - TSIP_SSESSION_SET_TO_OBJ(Refer_To->uri), - TSIP_SSESSION_SET_NULL()); - ret = tsip_api_invite_send_invite(self->ss_transf, self->ss_transf->media.type, - TSIP_ACTION_SET_NULL()); - - return ret; + self->ss_transf->owner = tsk_false;// not owned by the end-user -> will be destroyed as soon as the dialog dtor is called + + if(ret == 0) { + ret = tsip_invite_event_signal(tsip_i_ect_newcall, self->ss_transf, + tsip_event_code_dialog_request_outgoing, "ECTing", self->last_iRefer); + } + + ret = tsip_ssession_set(self->ss_transf, + TSIP_SSESSION_SET_TO_OBJ(Refer_To->uri), + TSIP_SSESSION_SET_NULL()); + ret = tsip_api_invite_send_invite(self->ss_transf, self->ss_transf->media.type, + TSIP_ACTION_SET_NULL()); + + return ret; } // iECTing -> (1xx lnotify) -> iECTing static int x0400_iECTing_2_iECTing_X_1xxfNOTIFY(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_response_t* response; + int ret; + tsip_dialog_invite_t *self; + const tsip_response_t* response; + + self = va_arg(*app, tsip_dialog_invite_t *); + response = va_arg(*app, const tsip_message_t *); - self = va_arg(*app, tsip_dialog_invite_t *); - response = va_arg(*app, const tsip_message_t *); - - // send NOTIFY (event if norefersub enabled) and alert user - ret = send_NOTIFY(self, TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response)); + // send NOTIFY (event if norefersub enabled) and alert user + ret = send_NOTIFY(self, TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response)); - return ret; + return ret; } // iECTing -> (23456 lnotify) -> Connected static int x0400_iECTing_2_Connected_X_23456fNOTIFY(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_response_t* response; - short code; - - self = va_arg(*app, tsip_dialog_invite_t *); - response = va_arg(*app, const tsip_message_t *); - code = TSIP_RESPONSE_CODE(response); - - // send NOTIFY (event if norefersub enabled) and alert user - ret = send_NOTIFY(self, code, TSIP_RESPONSE_PHRASE(response)); - - if(code >= 200 && code <= 299){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_completed, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), self->last_iRefer); - // hang up the call - ret = send_BYE(self); - } - else{ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_failed, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), self->last_iRefer); - } - - return ret; + int ret; + tsip_dialog_invite_t *self; + const tsip_response_t* response; + short code; + + self = va_arg(*app, tsip_dialog_invite_t *); + response = va_arg(*app, const tsip_message_t *); + code = TSIP_RESPONSE_CODE(response); + + // send NOTIFY (event if norefersub enabled) and alert user + ret = send_NOTIFY(self, code, TSIP_RESPONSE_PHRASE(response)); + + if(code >= 200 && code <= 299) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_completed, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), self->last_iRefer); + // hang up the call + ret = send_BYE(self); + } + else { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_i_ect_failed, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), self->last_iRefer); + } + + return ret; } @@ -387,101 +387,101 @@ static int x0400_iECTing_2_Connected_X_23456fNOTIFY(va_list *app) static int send_NOTIFY(tsip_dialog_invite_t *self, short code, const char* phrase) { - tsip_request_t *notify = tsk_null; - int ret = -1; - - if((notify = tsip_dialog_request_new(TSIP_DIALOG(self), "NOTIFY"))){ - char* sipfrag = tsk_null; - tsk_sprintf(&sipfrag, "%s %hi %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT, code, phrase); - ret = tsip_message_add_content(notify, "message/sipfrag", sipfrag, tsk_strlen(sipfrag)); - ret = tsip_dialog_request_send(TSIP_DIALOG(self), notify); - if(ret == 0){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, code, phrase, notify); - } - TSK_FREE(sipfrag); - TSK_OBJECT_SAFE_FREE(notify); - } - else{ - TSK_DEBUG_ERROR("Failed to create request"); - } - return ret; + tsip_request_t *notify = tsk_null; + int ret = -1; + + if((notify = tsip_dialog_request_new(TSIP_DIALOG(self), "NOTIFY"))) { + char* sipfrag = tsk_null; + tsk_sprintf(&sipfrag, "%s %hi %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT, code, phrase); + ret = tsip_message_add_content(notify, "message/sipfrag", sipfrag, tsk_strlen(sipfrag)); + ret = tsip_dialog_request_send(TSIP_DIALOG(self), notify); + if(ret == 0) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_o_ect_notify, code, phrase, notify); + } + TSK_FREE(sipfrag); + TSK_OBJECT_SAFE_FREE(notify); + } + else { + TSK_DEBUG_ERROR("Failed to create request"); + } + return ret; } static int send_REFER(tsip_dialog_invite_t *self, const char* to) { - int ret = 0; - tsip_request_t *refer = tsk_null; - tsip_uri_t* toUri = tsk_null; - - if(!self || !to){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!(toUri = tsip_uri_parse(to, tsk_strlen(to)))){ - TSK_DEBUG_ERROR("Failed to parse %s", to); - return -1; - } - else{ - // tsk_params_add_param(&toUri->params, "method", "INVITE"); - } - - if((refer = tsip_dialog_request_new(TSIP_DIALOG(self), "REFER"))){ - tsk_istr_t cid; - tsk_strrandom(&cid); - /* Add headers */ - tsip_message_add_headers(refer, - TSIP_HEADER_REFER_TO_VA_ARGS(toUri), - TSIP_HEADER_REFERRED_BY_VA_ARGS(TSIP_DIALOG_GET_STACK(self)->identity.impu, cid), - TSIP_HEADER_REFER_SUB_VA_ARGS(self->refersub), - tsk_null); - if(self->supported.norefersub){ - tsip_message_add_headers(refer, - TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub"), - tsk_null); - } - - ret = tsip_dialog_request_send(TSIP_DIALOG(self), refer); - TSK_OBJECT_SAFE_FREE(refer); - } - - TSK_OBJECT_SAFE_FREE(toUri); - return ret; + int ret = 0; + tsip_request_t *refer = tsk_null; + tsip_uri_t* toUri = tsk_null; + + if(!self || !to) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!(toUri = tsip_uri_parse(to, tsk_strlen(to)))) { + TSK_DEBUG_ERROR("Failed to parse %s", to); + return -1; + } + else { + // tsk_params_add_param(&toUri->params, "method", "INVITE"); + } + + if((refer = tsip_dialog_request_new(TSIP_DIALOG(self), "REFER"))) { + tsk_istr_t cid; + tsk_strrandom(&cid); + /* Add headers */ + tsip_message_add_headers(refer, + TSIP_HEADER_REFER_TO_VA_ARGS(toUri), + TSIP_HEADER_REFERRED_BY_VA_ARGS(TSIP_DIALOG_GET_STACK(self)->identity.impu, cid), + TSIP_HEADER_REFER_SUB_VA_ARGS(self->refersub), + tsk_null); + if(self->supported.norefersub) { + tsip_message_add_headers(refer, + TSIP_HEADER_SUPPORTED_VA_ARGS("norefersub"), + tsk_null); + } + + ret = tsip_dialog_request_send(TSIP_DIALOG(self), refer); + TSK_OBJECT_SAFE_FREE(refer); + } + + TSK_OBJECT_SAFE_FREE(toUri); + return ret; } static tsip_response_t * get_SipFragMessage(const tsip_request_t* notify) { - tsip_response_t *sipfrag = tsk_null; - if(TSIP_MESSAGE_HAS_CONTENT(notify) && tsk_striequals(notify->Content_Type->type, "message/sipfrag")){ - tsk_ragel_state_t state; - tsk_bool_t ret; - char* content = tsk_null; - - // sipfrag is a "tsip_message_t" with an extra \r\n - content = tsk_strndup(notify->Content->data, notify->Content->size); - if(tsk_strLastIndexOf(content, tsk_strlen(content), "\r\n") != tsk_strlen(content) - 2){//Hack for XXX buggy client - tsk_strcat(&content, "\r\n"); - } - tsk_strcat(&content, "\r\n"); - - tsk_ragel_state_init(&state, content, tsk_strlen(content)); - ret = tsip_message_parse(&state, &sipfrag, tsk_false); - TSK_FREE(content); - if(ret && TSIP_MESSAGE_IS_RESPONSE(sipfrag)){ - return sipfrag; - } - TSK_OBJECT_SAFE_FREE(sipfrag); - } - return sipfrag; + tsip_response_t *sipfrag = tsk_null; + if(TSIP_MESSAGE_HAS_CONTENT(notify) && tsk_striequals(notify->Content_Type->type, "message/sipfrag")) { + tsk_ragel_state_t state; + tsk_bool_t ret; + char* content = tsk_null; + + // sipfrag is a "tsip_message_t" with an extra \r\n + content = tsk_strndup(notify->Content->data, notify->Content->size); + if(tsk_strLastIndexOf(content, tsk_strlen(content), "\r\n") != tsk_strlen(content) - 2) { //Hack for XXX buggy client + tsk_strcat(&content, "\r\n"); + } + tsk_strcat(&content, "\r\n"); + + tsk_ragel_state_init(&state, content, tsk_strlen(content)); + ret = tsip_message_parse(&state, &sipfrag, tsk_false); + TSK_FREE(content); + if(ret && TSIP_MESSAGE_IS_RESPONSE(sipfrag)) { + return sipfrag; + } + TSK_OBJECT_SAFE_FREE(sipfrag); + } + return sipfrag; } static short get_SipFragResponseCode(const tsip_request_t* notify) { - tsip_response_t *sipfrag = get_SipFragMessage(notify); - short code = 0; - if(sipfrag){ - code = TSIP_RESPONSE_CODE(sipfrag); - TSK_OBJECT_SAFE_FREE(sipfrag); - } - return code; + tsip_response_t *sipfrag = get_SipFragMessage(notify); + short code = 0; + if(sipfrag) { + code = TSIP_RESPONSE_CODE(sipfrag); + TSK_OBJECT_SAFE_FREE(sipfrag); + } + return code; }
\ No newline at end of file diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.hold.c b/tinySIP/src/dialogs/tsip_dialog_invite.hold.c index 7845bab..e0558fc 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.hold.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.hold.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. * @@ -22,7 +22,7 @@ /**@file tsip_dialog_invite.hold.c * @brief Communication Hold (3GPP TS 24.610) - * The Communication Hold supplementary service enables a user to suspend the reception of media stream(s) of an established IP multimedia session, + * The Communication Hold supplementary service enables a user to suspend the reception of media stream(s) of an established IP multimedia session, * and resume the media stream(s) at a later time. * * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> @@ -46,7 +46,7 @@ static int x0150_Any_2_Any_X_i422(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_is_resp2INVITEorUPDATE(tsip_dialog_invite_t* self, tsip_message_t* message) { - return (TSIP_RESPONSE_IS_TO_INVITE(message) || TSIP_RESPONSE_IS_TO_UPDATE(message)); + return (TSIP_RESPONSE_IS_TO_INVITE(message) || TSIP_RESPONSE_IS_TO_UPDATE(message)); } /* ======================== external functions ======================== */ @@ -56,31 +56,31 @@ extern int send_ACK(tsip_dialog_invite_t *self, const tsip_response_t* r2xxINVIT int tsip_dialog_invite_hold_init(tsip_dialog_invite_t *self) { - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Hold === - */ - // Connected -> (send HOLD) -> Holding - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oHold, _fsm_state_Holding, x0100_Connected_2_Holding_X_oHold, "x0100_Connected_2_Holding_X_oHold"), - // Holding -> (i2xx) -> Connected - TSK_FSM_ADD(_fsm_state_Holding, _fsm_action_i2xx, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0101_Holding_2_Connected_X_ixxx, "x0101_Holding_2_Connected_X_ixxx"), - // Holding -> (i300-699) -> Connected - TSK_FSM_ADD(_fsm_state_Holding, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0101_Holding_2_Connected_X_ixxx, "x0101_Holding_2_Connected_X_ixxx"), - - /*======================= - * === Resume === - */ - // Connected -> (send RESUME) -> Resuming - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oResume, _fsm_state_Resuming, x0102_Connected_2_Resuming_X_oResume, "x0102_Connected_2_Resuming_X_oResume"), - // Resuming -> (i2xx) -> Connected - TSK_FSM_ADD(_fsm_state_Resuming, _fsm_action_i2xx, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0103_Resuming_2_Connected_X_ixxx, "x0103_Resuming_2_Connected_X_ixxx"), - // Resuming -> (i300-699) -> Connected - TSK_FSM_ADD(_fsm_state_Resuming, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0103_Resuming_2_Connected_X_ixxx, "x0103_Resuming_2_Connected_X_ixxx"), - - TSK_FSM_ADD_NULL()); - - return 0; + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Hold === + */ + // Connected -> (send HOLD) -> Holding + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oHold, _fsm_state_Holding, x0100_Connected_2_Holding_X_oHold, "x0100_Connected_2_Holding_X_oHold"), + // Holding -> (i2xx) -> Connected + TSK_FSM_ADD(_fsm_state_Holding, _fsm_action_i2xx, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0101_Holding_2_Connected_X_ixxx, "x0101_Holding_2_Connected_X_ixxx"), + // Holding -> (i300-699) -> Connected + TSK_FSM_ADD(_fsm_state_Holding, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0101_Holding_2_Connected_X_ixxx, "x0101_Holding_2_Connected_X_ixxx"), + + /*======================= + * === Resume === + */ + // Connected -> (send RESUME) -> Resuming + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oResume, _fsm_state_Resuming, x0102_Connected_2_Resuming_X_oResume, "x0102_Connected_2_Resuming_X_oResume"), + // Resuming -> (i2xx) -> Connected + TSK_FSM_ADD(_fsm_state_Resuming, _fsm_action_i2xx, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0103_Resuming_2_Connected_X_ixxx, "x0103_Resuming_2_Connected_X_ixxx"), + // Resuming -> (i300-699) -> Connected + TSK_FSM_ADD(_fsm_state_Resuming, _fsm_action_i300_to_i699, _fsm_cond_is_resp2INVITEorUPDATE, _fsm_state_Connected, x0103_Resuming_2_Connected_X_ixxx, "x0103_Resuming_2_Connected_X_ixxx"), + + TSK_FSM_ADD_NULL()); + + return 0; } @@ -92,159 +92,159 @@ int tsip_dialog_invite_hold_init(tsip_dialog_invite_t *self) // Connected -> (send HOLD) -> Holding int x0100_Connected_2_Holding_X_oHold(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_action_t* action; + int ret; + 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 *); - if(!self->msession_mgr){ - TSK_DEBUG_WARN("Media Session manager is Null"); - return 0; - } + if(!self->msession_mgr) { + TSK_DEBUG_WARN("Media Session manager is Null"); + return 0; + } - /* put on hold */ - ret = tmedia_session_mgr_hold(self->msession_mgr, action->media.type); + /* put on hold */ + ret = tmedia_session_mgr_hold(self->msession_mgr, action->media.type); - /* send the request */ - if((ret = send_INVITE(self, tsk_false))){ - // FIXME: signal error without breaking the state machine - } + /* send the request */ + if((ret = send_INVITE(self, tsk_false))) { + // FIXME: signal error without breaking the state machine + } - return 0; + return 0; } // Holding -> (ixxx) -> Connected int x0101_Holding_2_Connected_X_ixxx(va_list *app) { - int ret; - - tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t* response = va_arg(*app, const tsip_response_t *); - - /* reset current action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - - /* Process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, response))){ - /* Send error */ - return ret; - } - else if(TSIP_RESPONSE_IS_TO_INVITE(response)){ - /* send ACK */ - ret = send_ACK(self, response); - } - - /* alert the user */ - if(TSIP_RESPONSE_IS_2XX(response)){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_hold_ok, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - self->hold.local = tsk_true; - } - else{ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_hold_nok, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - self->hold.local = tsk_false; - } - - return ret; + int ret; + + tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t* response = va_arg(*app, const tsip_response_t *); + + /* reset current action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + + /* Process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, response))) { + /* Send error */ + return ret; + } + else if(TSIP_RESPONSE_IS_TO_INVITE(response)) { + /* send ACK */ + ret = send_ACK(self, response); + } + + /* alert the user */ + if(TSIP_RESPONSE_IS_2XX(response)) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_hold_ok, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + self->hold.local = tsk_true; + } + else { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_hold_nok, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + self->hold.local = tsk_false; + } + + return ret; } // Connected -> (send RESUME) -> Resuming int x0102_Connected_2_Resuming_X_oResume(va_list *app) { - int ret; - tsip_dialog_invite_t *self; - const tsip_action_t* action; + int ret; + 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 *); - if(!self->msession_mgr){ - TSK_DEBUG_WARN("Media Session manager is Null"); - return 0; - } + if(!self->msession_mgr) { + TSK_DEBUG_WARN("Media Session manager is Null"); + return 0; + } - /* Resume both */ - ret = tmedia_session_mgr_resume(self->msession_mgr, action->media.type, tsk_true); - ret = tmedia_session_mgr_resume(self->msession_mgr, action->media.type, tsk_false); + /* Resume both */ + ret = tmedia_session_mgr_resume(self->msession_mgr, action->media.type, tsk_true); + ret = tmedia_session_mgr_resume(self->msession_mgr, action->media.type, tsk_false); - /* send the request */ - if((ret = send_INVITE(self, tsk_false))){ - // FIXME: signal error without breaking the state machine - } + /* send the request */ + if((ret = send_INVITE(self, tsk_false))) { + // FIXME: signal error without breaking the state machine + } - return 0; + return 0; } // Resuming -> (ixxx) -> Connected int x0103_Resuming_2_Connected_X_ixxx(va_list *app) { - int ret; - - tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); - const tsip_response_t* response = va_arg(*app, const tsip_response_t *); - - /* reset current action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - - /* Process remote offer */ - if((ret = tsip_dialog_invite_process_ro(self, response))){ - /* Send error */ - return ret; - } - else if(TSIP_RESPONSE_IS_TO_INVITE(response)){ - /* send ACK */ - ret = send_ACK(self, response); - } - - /* alert the user */ - if(TSIP_RESPONSE_IS_2XX(response)){ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_resume_ok, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - self->hold.local = tsk_false; - } - else{ - TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_resume_nok, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - self->hold.local = tsk_true; - } - - return ret; + int ret; + + tsip_dialog_invite_t* self = va_arg(*app, tsip_dialog_invite_t *); + const tsip_response_t* response = va_arg(*app, const tsip_response_t *); + + /* reset current action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + + /* Process remote offer */ + if((ret = tsip_dialog_invite_process_ro(self, response))) { + /* Send error */ + return ret; + } + else if(TSIP_RESPONSE_IS_TO_INVITE(response)) { + /* send ACK */ + ret = send_ACK(self, response); + } + + /* alert the user */ + if(TSIP_RESPONSE_IS_2XX(response)) { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_resume_ok, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + self->hold.local = tsk_false; + } + else { + TSIP_DIALOG_INVITE_SIGNAL(self, tsip_m_local_resume_nok, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + self->hold.local = tsk_true; + } + + return ret; } /* handle requests/responses (MUST be called after set_ro()) */ int tsip_dialog_invite_hold_handle(tsip_dialog_invite_t* self, const tsip_request_t* rINVITEorUPDATE) { - tsk_bool_t remote_hold, bodiless_invite; - int ret = 0; - - if(!self || !rINVITEorUPDATE || !self->msession_mgr){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - remote_hold = tmedia_session_mgr_is_held(self->msession_mgr, self->msession_mgr->type, tsk_false); - - // resume the call if we receive bodiless INVITE - bodiless_invite = !TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE) && TSIP_REQUEST_IS_INVITE(rINVITEorUPDATE); - if(bodiless_invite && remote_hold){ - // resume remote - if((ret = tmedia_session_mgr_resume(self->msession_mgr, self->msession_mgr->type, tsk_false)) == 0){ - remote_hold = tsk_false; - } - } - - if(ret == 0 && (remote_hold != self->hold.remote)){ - self->hold.remote = remote_hold; - TSIP_DIALOG_INVITE_SIGNAL(self, self->hold.remote ? tsip_m_remote_hold : tsip_m_remote_resume, - tsip_event_code_dialog_request_incoming, "Hold/Resume state changed", rINVITEorUPDATE); - } - - return ret; + tsk_bool_t remote_hold, bodiless_invite; + int ret = 0; + + if(!self || !rINVITEorUPDATE || !self->msession_mgr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + remote_hold = tmedia_session_mgr_is_held(self->msession_mgr, self->msession_mgr->type, tsk_false); + + // resume the call if we receive bodiless INVITE + bodiless_invite = !TSIP_MESSAGE_HAS_CONTENT(rINVITEorUPDATE) && TSIP_REQUEST_IS_INVITE(rINVITEorUPDATE); + if(bodiless_invite && remote_hold) { + // resume remote + if((ret = tmedia_session_mgr_resume(self->msession_mgr, self->msession_mgr->type, tsk_false)) == 0) { + remote_hold = tsk_false; + } + } + + if(ret == 0 && (remote_hold != self->hold.remote)) { + self->hold.remote = remote_hold; + TSIP_DIALOG_INVITE_SIGNAL(self, self->hold.remote ? tsip_m_remote_hold : tsip_m_remote_resume, + tsip_event_code_dialog_request_incoming, "Hold/Resume state changed", rINVITEorUPDATE); + } + + return ret; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.ice.c b/tinySIP/src/dialogs/tsip_dialog_invite.ice.c index 823e548..c68d8cd 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.ice.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.ice.c @@ -48,7 +48,7 @@ tsip_dialog_invite_ice_set_silent_mode_ctx((_self), tsk_true); \ tsip_dialog_invite_ice_cancel_ctx((_self)); /* "cancelled" event will not be sent and we're sure that cancel operation will be done when the function exit */ \ tsip_dialog_invite_ice_set_sync_mode_ctx((_self), tsk_false); \ tsip_dialog_invite_ice_set_silent_mode_ctx((_self), tsk_false); \ - + /* ======================== transitions ======================== */ // Use "Current" instead of "Any" to avoid priority reordering static int x0500_Current_2_Current_X_oINVITE(va_list *app); @@ -57,46 +57,46 @@ static int x0500_Current_2_Current_X_iINVITE(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_get_local_candidates(tsip_dialog_invite_t* self, tsip_message_t* message) { - if(self->supported.ice){ + if(self->supported.ice) { tsk_bool_t use_ice = tsk_false; // "action->media.type" will be defined for locally initiated media update tmedia_type_t new_media = TSIP_DIALOG(self)->curr_action ? TSIP_DIALOG(self)->curr_action->media.type : tmedia_none; - - if(message && TSIP_MESSAGE_HAS_CONTENT(message) && tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))){ + + if(message && TSIP_MESSAGE_HAS_CONTENT(message) && tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))) { // If this code is called this means that we are the "answerer" // only gets the candidates if ICE is enabled and the remote peer supports ICE tsdp_message_t* sdp_ro; const tsdp_header_M_t* M; int index; - if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))){ + if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))) { TSK_DEBUG_ERROR("Failed to parse remote sdp message"); return tsk_false; } - + index = 0; - while((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp_ro, tsdp_htype_M, index++))){ - if(!tsdp_header_M_findA(M, "candidate")){ + while((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp_ro, tsdp_htype_M, index++))) { + if(!tsdp_header_M_findA(M, "candidate")) { use_ice = tsk_false; // do not use ICE if at least on media is ICE-less (e.g. MSRP) break; } use_ice = tsk_true; // only use ICE if there is a least one media line } - + new_media = tmedia_type_from_sdp(sdp_ro); - + TSK_OBJECT_SAFE_FREE(sdp_ro); } - else if(!message){ + else if(!message) { // we are the "offerer" -> use ICE only for audio or video medias (ignore ice for MSRP) use_ice = (new_media & tmedia_audio) || (new_media & tmedia_video); } - - if(use_ice){ - if(!self->ice.ctx_audio && !self->ice.ctx_video){ // First time + + if(use_ice) { + if(!self->ice.ctx_audio && !self->ice.ctx_video) { // First time return tsk_true; } - else{ - if(self->ice.media_type != new_media){ + else { + if(self->ice.media_type != new_media) { return tsk_true; } return !tsip_dialog_invite_ice_got_local_candidates(self); @@ -113,17 +113,17 @@ int tsip_dialog_invite_ice_init(tsip_dialog_invite_t *self) TSK_FSM_ADD(tsk_fsm_state_current, _fsm_action_oINVITE, _fsm_cond_get_local_candidates, tsk_fsm_state_current, x0500_Current_2_Current_X_oINVITE, "x0500_Current_2_Current_X_oINVITE"), // Current -> (iINVITE) -> Current TSK_FSM_ADD(tsk_fsm_state_current, _fsm_action_iINVITE, _fsm_cond_get_local_candidates, tsk_fsm_state_current, x0500_Current_2_Current_X_iINVITE, "x0500_Current_2_Current_X_iINVITE") - ); - + ); + return 0; } int tsip_dialog_invite_ice_timers_set(tsip_dialog_invite_t *self, int64_t timeout) { - if(/*tnet_ice_ctx_is_active*/(self->ice.ctx_audio)){ + if(/*tnet_ice_ctx_is_active*/(self->ice.ctx_audio)) { tnet_ice_ctx_set_concheck_timeout(self->ice.ctx_audio, timeout); } - if(/*tnet_ice_ctx_is_active*/(self->ice.ctx_video)){ + if(/*tnet_ice_ctx_is_active*/(self->ice.ctx_video)) { tnet_ice_ctx_set_concheck_timeout(self->ice.ctx_video, timeout); } return 0; @@ -133,14 +133,14 @@ static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia { int32_t transport_idx; int ret = 0; - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; if (!self->ice.ctx_audio && (media_type & tmedia_audio)) { self->ice.ctx_audio = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), - self->use_rtcp, tsk_false, tsip_dialog_invite_ice_audio_callback, self); + self->use_rtcp, tsk_false, tsip_dialog_invite_ice_audio_callback, self); if (!self->ice.ctx_audio) { TSK_DEBUG_ERROR("Failed to create ICE audio context"); return -2; @@ -149,14 +149,14 @@ static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia ret = tnet_ice_ctx_set_stun(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.stun.hostname, TSIP_DIALOG_GET_SS(self)->media.stun.port, kStunSoftware, TSIP_DIALOG_GET_SS(self)->media.stun.username, TSIP_DIALOG_GET_SS(self)->media.stun.password); #else ret = tnet_ice_ctx_add_server( - self->ice.ctx_audio, - "udp", // "tcp", "tls", "ws", "wss"... - TSIP_DIALOG_GET_SS(self)->media.stun.hostname, - TSIP_DIALOG_GET_SS(self)->media.stun.port, - TSIP_DIALOG_GET_SS(self)->media.enable_iceturn, - TSIP_DIALOG_GET_SS(self)->media.enable_icestun, - TSIP_DIALOG_GET_SS(self)->media.stun.username, - TSIP_DIALOG_GET_SS(self)->media.stun.password); + self->ice.ctx_audio, + "udp", // "tcp", "tls", "ws", "wss"... + TSIP_DIALOG_GET_SS(self)->media.stun.hostname, + TSIP_DIALOG_GET_SS(self)->media.stun.port, + TSIP_DIALOG_GET_SS(self)->media.enable_iceturn, + TSIP_DIALOG_GET_SS(self)->media.enable_icestun, + TSIP_DIALOG_GET_SS(self)->media.stun.username, + TSIP_DIALOG_GET_SS(self)->media.stun.password); #endif ret = tnet_ice_ctx_set_turn_enabled(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.enable_iceturn); ret = tnet_ice_ctx_set_stun_enabled(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.enable_icestun); @@ -164,7 +164,7 @@ static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia } if (!self->ice.ctx_video && (media_type & tmedia_video)) { self->ice.ctx_video = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), - self->use_rtcp, tsk_true, tsip_dialog_invite_ice_video_callback, self); + self->use_rtcp, tsk_true, tsip_dialog_invite_ice_video_callback, self); if (!self->ice.ctx_video) { TSK_DEBUG_ERROR("Failed to create ICE video context"); return -2; @@ -173,50 +173,50 @@ static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia ret = tnet_ice_ctx_set_stun(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.stun.hostname, TSIP_DIALOG_GET_SS(self)->media.stun.port, kStunSoftware, TSIP_DIALOG_GET_SS(self)->media.stun.username, TSIP_DIALOG_GET_SS(self)->media.stun.password); #else ret = tnet_ice_ctx_add_server( - self->ice.ctx_video, - "udp", // "tcp", "tls", "ws", "wss"... - TSIP_DIALOG_GET_SS(self)->media.stun.hostname, - TSIP_DIALOG_GET_SS(self)->media.stun.port, - TSIP_DIALOG_GET_SS(self)->media.enable_iceturn, - TSIP_DIALOG_GET_SS(self)->media.enable_icestun, - TSIP_DIALOG_GET_SS(self)->media.stun.username, - TSIP_DIALOG_GET_SS(self)->media.stun.password); + self->ice.ctx_video, + "udp", // "tcp", "tls", "ws", "wss"... + TSIP_DIALOG_GET_SS(self)->media.stun.hostname, + TSIP_DIALOG_GET_SS(self)->media.stun.port, + TSIP_DIALOG_GET_SS(self)->media.enable_iceturn, + TSIP_DIALOG_GET_SS(self)->media.enable_icestun, + TSIP_DIALOG_GET_SS(self)->media.stun.username, + TSIP_DIALOG_GET_SS(self)->media.stun.password); #endif ret = tnet_ice_ctx_set_turn_enabled(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.enable_iceturn); ret = tnet_ice_ctx_set_stun_enabled(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.enable_icestun); ret = tnet_ice_ctx_set_rtcpmux(self->ice.ctx_video, self->use_rtcpmux); } - + // set media type ret = tsip_dialog_invite_ice_set_media_type(self, media_type); - + // update session manager with the right ICE contexts if (self->msession_mgr) { ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); } - + return ret; } int tsip_dialog_invite_ice_set_media_type(tsip_dialog_invite_t * self, tmedia_type_t _media_type) { - if(self){ + if(self) { tmedia_type_t av_media_type = (_media_type & tmedia_audiovideo); // filter to keep audio and video only // "none" comparison is used to exclude the "first call" - if(self->ice.media_type != tmedia_none && self->ice.media_type != av_media_type){ + if(self->ice.media_type != tmedia_none && self->ice.media_type != av_media_type) { // cancels contexts associated to old medias - if(self->ice.ctx_audio && !(av_media_type & tmedia_audio)){ + if(self->ice.ctx_audio && !(av_media_type & tmedia_audio)) { tnet_ice_ctx_cancel(self->ice.ctx_audio); } - if(self->ice.ctx_video && !(av_media_type & tmedia_video)){ + if(self->ice.ctx_video && !(av_media_type & tmedia_video)) { tnet_ice_ctx_cancel(self->ice.ctx_video); } // cancels contexts associated to new medias (e.g. session "remove" then "add") // cancel() on newly created contexts don't have any effect - if(self->ice.ctx_audio && (!(av_media_type & tmedia_audio) && (self->ice.media_type & tmedia_audio))){ + if(self->ice.ctx_audio && (!(av_media_type & tmedia_audio) && (self->ice.media_type & tmedia_audio))) { //tnet_ice_ctx_cancel(self->ice.ctx_audio); } - if(self->ice.ctx_video && (!(av_media_type & tmedia_video) && (self->ice.media_type & tmedia_video))){ + if(self->ice.ctx_video && (!(av_media_type & tmedia_video) && (self->ice.media_type & tmedia_video))) { //tnet_ice_ctx_cancel(self->ice.ctx_video); } } @@ -228,14 +228,14 @@ int tsip_dialog_invite_ice_set_media_type(tsip_dialog_invite_t * self, tmedia_ty static int tsip_dialog_invite_ice_start_ctx(tsip_dialog_invite_t * self) { int ret = 0; - if(self){ - if((self->ice.media_type & tmedia_audio)){ - if(self->ice.ctx_audio && (ret = tnet_ice_ctx_start(self->ice.ctx_audio)) != 0){ + if(self) { + if((self->ice.media_type & tmedia_audio)) { + if(self->ice.ctx_audio && (ret = tnet_ice_ctx_start(self->ice.ctx_audio)) != 0) { return ret; } } - if((self->ice.media_type & tmedia_video)){ - if(self->ice.ctx_video && (ret = tnet_ice_ctx_start(self->ice.ctx_video)) != 0){ + if((self->ice.media_type & tmedia_video)) { + if(self->ice.ctx_video && (ret = tnet_ice_ctx_start(self->ice.ctx_video)) != 0) { return ret; } } @@ -246,14 +246,14 @@ static int tsip_dialog_invite_ice_start_ctx(tsip_dialog_invite_t * self) static int tsip_dialog_invite_ice_cancel_ctx(tsip_dialog_invite_t * self) { int ret = 0; - if(self){ - if((self->ice.media_type & tmedia_audio)){ - if(self->ice.ctx_audio && (ret = tnet_ice_ctx_cancel(self->ice.ctx_audio)) != 0){ + if(self) { + if((self->ice.media_type & tmedia_audio)) { + if(self->ice.ctx_audio && (ret = tnet_ice_ctx_cancel(self->ice.ctx_audio)) != 0) { return ret; } } - if((self->ice.media_type & tmedia_video)){ - if(self->ice.ctx_video && (ret = tnet_ice_ctx_cancel(self->ice.ctx_video)) != 0){ + if((self->ice.media_type & tmedia_video)) { + if(self->ice.ctx_video && (ret = tnet_ice_ctx_cancel(self->ice.ctx_video)) != 0) { return ret; } } @@ -264,14 +264,14 @@ static int tsip_dialog_invite_ice_cancel_ctx(tsip_dialog_invite_t * self) static int tsip_dialog_invite_ice_set_sync_mode_ctx(tsip_dialog_invite_t * self, tsk_bool_t sync_mode) { int ret = 0; - if(self){ - if((self->ice.media_type & tmedia_audio)){ - if(self->ice.ctx_audio && (ret = tnet_ice_ctx_set_sync_mode(self->ice.ctx_audio, sync_mode)) != 0){ + if(self) { + if((self->ice.media_type & tmedia_audio)) { + if(self->ice.ctx_audio && (ret = tnet_ice_ctx_set_sync_mode(self->ice.ctx_audio, sync_mode)) != 0) { return ret; } } - if((self->ice.media_type & tmedia_video)){ - if(self->ice.ctx_video && (ret = tnet_ice_ctx_set_sync_mode(self->ice.ctx_video, sync_mode)) != 0){ + if((self->ice.media_type & tmedia_video)) { + if(self->ice.ctx_video && (ret = tnet_ice_ctx_set_sync_mode(self->ice.ctx_video, sync_mode)) != 0) { return ret; } } @@ -282,14 +282,14 @@ static int tsip_dialog_invite_ice_set_sync_mode_ctx(tsip_dialog_invite_t * self, static int tsip_dialog_invite_ice_set_silent_mode_ctx(tsip_dialog_invite_t * self, tsk_bool_t silent_mode) { int ret = 0; - if(self){ - if((self->ice.media_type & tmedia_audio)){ - if(self->ice.ctx_audio && (ret = tnet_ice_ctx_set_silent_mode(self->ice.ctx_audio, silent_mode)) != 0){ + if(self) { + if((self->ice.media_type & tmedia_audio)) { + if(self->ice.ctx_audio && (ret = tnet_ice_ctx_set_silent_mode(self->ice.ctx_audio, silent_mode)) != 0) { return ret; } } - if((self->ice.media_type & tmedia_video)){ - if(self->ice.ctx_video && (ret = tnet_ice_ctx_set_silent_mode(self->ice.ctx_video, silent_mode)) != 0){ + if((self->ice.media_type & tmedia_video)) { + if(self->ice.ctx_video && (ret = tnet_ice_ctx_set_silent_mode(self->ice.ctx_video, silent_mode)) != 0) { return ret; } } @@ -299,7 +299,7 @@ static int tsip_dialog_invite_ice_set_silent_mode_ctx(tsip_dialog_invite_t * sel tsk_bool_t tsip_dialog_invite_ice_is_enabled(const tsip_dialog_invite_t * self) { - if(self){ + if(self) { return (self->supported.ice && (tnet_ice_ctx_is_active(self->ice.ctx_audio) || tnet_ice_ctx_is_active(self->ice.ctx_video))); } return tsk_false; @@ -307,37 +307,37 @@ tsk_bool_t tsip_dialog_invite_ice_is_enabled(const tsip_dialog_invite_t * self) tsk_bool_t tsip_dialog_invite_ice_is_connected(const tsip_dialog_invite_t * self) { - if(self){ + if(self) { return (!tnet_ice_ctx_is_active(self->ice.ctx_audio) || tnet_ice_ctx_is_connected(self->ice.ctx_audio)) - && (!tnet_ice_ctx_is_active(self->ice.ctx_video) || tnet_ice_ctx_is_connected(self->ice.ctx_video)); + && (!tnet_ice_ctx_is_active(self->ice.ctx_video) || tnet_ice_ctx_is_connected(self->ice.ctx_video)); } return tsk_false; } tsk_bool_t tsip_dialog_invite_ice_got_local_candidates(const tsip_dialog_invite_t * self) { - if(self){ + if(self) { return (!tnet_ice_ctx_is_active(self->ice.ctx_audio) || tnet_ice_ctx_got_local_candidates(self->ice.ctx_audio)) - && (!tnet_ice_ctx_is_active(self->ice.ctx_video) || tnet_ice_ctx_got_local_candidates(self->ice.ctx_video)); + && (!tnet_ice_ctx_is_active(self->ice.ctx_video) || tnet_ice_ctx_got_local_candidates(self->ice.ctx_video)); } return tsk_false; } int tsip_dialog_invite_ice_save_action(tsip_dialog_invite_t * self, tsk_fsm_action_id action_id, const tsip_action_t* action, const tsip_message_t* message) { - if(!self){ + if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + // There are good reasons to ref() the action and message before safe_free() // /!\ do not change - + self->ice.last_action_id = action_id; action = tsk_object_ref((tsk_object_t*)action); TSK_OBJECT_SAFE_FREE(self->ice.last_action); self->ice.last_action = (tsip_action_t*)action; - + message = tsk_object_ref((tsk_object_t*)message); TSK_OBJECT_SAFE_FREE(self->ice.last_message); self->ice.last_message = (tsip_message_t*)message; @@ -349,30 +349,30 @@ int tsip_dialog_invite_ice_process_lo(tsip_dialog_invite_t * self, const tsdp_me const tsdp_header_M_t* M; const tsdp_header_A_t *A; int ret = 0, i; - - if(!self || !sdp_lo){ + + if(!self || !sdp_lo) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + // cancels all ICE contexts without candidates // this happens if codecs negotiations mismatch for one media out of two or three - for(i = 0; i < 2; ++i){ + for(i = 0; i < 2; ++i) { struct tnet_ice_ctx_s *ctx = i == 0 ? self->ice.ctx_audio : self->ice.ctx_video; const char* media = i == 0 ? "audio" : "video"; - if(tnet_ice_ctx_is_active(ctx)){ + if(tnet_ice_ctx_is_active(ctx)) { tsk_bool_t cancel = tsk_true; - if((M = tsdp_message_find_media(sdp_lo, media))){ - if((A = tsdp_header_M_findA(M, "candidate"))){ + if((M = tsdp_message_find_media(sdp_lo, media))) { + if((A = tsdp_header_M_findA(M, "candidate"))) { cancel = tsk_false; } } - if(cancel){ + if(cancel) { ret = tnet_ice_ctx_cancel(ctx); } } } - + return ret; } @@ -387,57 +387,57 @@ int tsip_dialog_invite_ice_process_ro(tsip_dialog_invite_t * self, const tsdp_me const char* sess_pwd = tsk_null; int ret = 0, i; struct tnet_ice_ctx_s *ctx; - - if(!self || !sdp_ro){ + + if(!self || !sdp_ro) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - if(!self->ice.ctx_audio && !self->ice.ctx_video){ + if(!self->ice.ctx_audio && !self->ice.ctx_video) { return 0; } - + // make sure this is different SDP - if((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp_ro, tsdp_htype_O))){ - if(self->ice.last_sdp_ro_ver == (int32_t)O->sess_version){ + if((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp_ro, tsdp_htype_O))) { + if(self->ice.last_sdp_ro_ver == (int32_t)O->sess_version) { TSK_DEBUG_INFO("ICE: ignore processing SDP RO because version haven't changed"); return 0; } self->ice.last_sdp_ro_ver = (int32_t)O->sess_version; } - + // session level attributes - - if((A = tsdp_message_get_headerA(sdp_ro, "ice-ufrag"))){ + + if((A = tsdp_message_get_headerA(sdp_ro, "ice-ufrag"))) { sess_ufrag = A->value; } - if((A = tsdp_message_get_headerA(sdp_ro, "ice-pwd"))){ + if((A = tsdp_message_get_headerA(sdp_ro, "ice-pwd"))) { sess_pwd = A->value; } - + #if 0 // Use RTCWeb Profile (tmedia_profile_rtcweb) { const tsdp_header_S_t *S; - if((S = (const tsdp_header_S_t *)tsdp_message_get_header(sdp_ro, tsdp_htype_S)) && S->value){ + if((S = (const tsdp_header_S_t *)tsdp_message_get_header(sdp_ro, tsdp_htype_S)) && S->value) { self->ice.is_jingle = tsk_strcontains(S->value, tsk_strlen(S->value), "webrtc"); } } #endif - - for(i = 0; i < 2; ++i){ - if((M = tsdp_message_find_media(sdp_ro, i==0 ? "audio": "video"))){ + + for(i = 0; i < 2; ++i) { + if((M = tsdp_message_find_media(sdp_ro, i==0 ? "audio": "video"))) { const char *ufrag = sess_ufrag, *pwd = sess_pwd; tsk_bool_t remote_use_rtcpmux = (tsdp_header_M_findA(M, "rtcp-mux") != tsk_null); ctx = (i==0 ? self->ice.ctx_audio : self->ice.ctx_video); ice_remote_candidates = tsk_null; index = 0; - if((A = tsdp_header_M_findA(M, "ice-ufrag"))){ + if((A = tsdp_header_M_findA(M, "ice-ufrag"))) { ufrag = A->value; } - if((A = tsdp_header_M_findA(M, "ice-pwd"))){ + if((A = tsdp_header_M_findA(M, "ice-pwd"))) { pwd = A->value; } - - while((A = tsdp_header_M_findA_at(M, "candidate", index++))){ + + while((A = tsdp_header_M_findA_at(M, "candidate", index++))) { tsk_strcat_2(&ice_remote_candidates, "%s\r\n", A->value); } // ICE processing will be automatically stopped if the remote candidates are not valid @@ -446,7 +446,7 @@ int tsip_dialog_invite_ice_process_ro(tsip_dialog_invite_t * self, const tsdp_me TSK_SAFE_FREE(ice_remote_candidates); } } - + return ret; } @@ -465,35 +465,35 @@ static int x0500_Current_2_Current_X_oINVITE(va_list *app) const tsip_message_t *message; tmedia_type_t media_type; static const tsk_bool_t __force_restart_is_yes = tsk_true; - + self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); - + media_type = (action && action->media.type != tmedia_none) ? action->media.type : TSIP_DIALOG_GET_SS(self)->media.type; self->is_client = tsk_true; tsip_dialog_invite_ice_save_action(self, _fsm_action_oINVITE, action, message); - + // Cancel without notifying ("silent mode") and perform the operation right now ("sync mode") tsip_dialog_invite_ice_cancel_silent_and_sync_ctx(self); - + // create ICE context - if((ret = tsip_dialog_invite_ice_create_ctx(self, media_type))){ + if((ret = tsip_dialog_invite_ice_create_ctx(self, media_type))) { TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } - + // For now disable ICE timers until we receive the 2xx ret = tsip_dialog_invite_ice_timers_set(self, -1); - + // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); - + // alert the user only if we are in initial state which means that it's not media update - if(TSIP_DIALOG(self)->state == tsip_initial){ + if(TSIP_DIALOG(self)->state == tsip_initial) { TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); } - + return ret; } @@ -504,45 +504,45 @@ static int x0500_Current_2_Current_X_iINVITE(va_list *app) tsip_dialog_invite_t *self; const tsip_action_t* action; const tsip_message_t *message; - + self = va_arg(*app, tsip_dialog_invite_t *); message = va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); - + self->is_client = tsk_false; ret = tsip_dialog_invite_ice_save_action(self, _fsm_action_iINVITE, action, message); - + // Cancel without notifying ("silent mode") and perform the operation right now ("sync mode") tsip_dialog_invite_ice_cancel_silent_and_sync_ctx(self); - + // set remote candidates - if(TSIP_MESSAGE_HAS_CONTENT(message)){ - if(tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))){ + if(TSIP_MESSAGE_HAS_CONTENT(message)) { + if(tsk_striequals("application/sdp", TSIP_MESSAGE_CONTENT_TYPE(message))) { tsdp_message_t* sdp_ro; - if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))){ + if(!(sdp_ro = tsdp_message_parse(TSIP_MESSAGE_CONTENT_DATA(message), TSIP_MESSAGE_CONTENT_DATA_LENGTH(message)))) { TSK_DEBUG_ERROR("Failed to parse remote sdp message"); return -2; } // create ICE context - if((ret = tsip_dialog_invite_ice_create_ctx(self, tmedia_type_from_sdp(sdp_ro)))){ + if((ret = tsip_dialog_invite_ice_create_ctx(self, tmedia_type_from_sdp(sdp_ro)))) { TSK_DEBUG_ERROR("tsip_dialog_invite_ice_create_ctx() failed"); return ret; } ret = tsip_dialog_invite_ice_process_ro(self, sdp_ro, tsk_true); TSK_OBJECT_SAFE_FREE(sdp_ro); } - else{ + else { TSK_DEBUG_ERROR("[%s] content-type is not supportted", TSIP_MESSAGE_CONTENT_TYPE(message)); return -3; } } - + // For now disable ICE timers until we send the 2xx and receive the ACK ret = tsip_dialog_invite_ice_timers_set(self, -1); - + // Start ICE ret = tsip_dialog_invite_ice_start_ctx(self); - + return ret; } @@ -557,52 +557,50 @@ static int tsip_dialog_invite_ice_callback(const tnet_ice_event_t *e) { int ret = 0; tsip_dialog_invite_t *dialog; - + TSK_DEBUG_INFO("ICE callback: %s", e->phrase); - + dialog = tsk_object_ref(TSK_OBJECT(e->userdata)); - + // Do not lock: caller is thread safe - - switch(e->type){ - case tnet_ice_event_type_gathering_completed: - case tnet_ice_event_type_conncheck_succeed: - case tnet_ice_event_type_conncheck_failed: - case tnet_ice_event_type_cancelled: - { - if(dialog->ice.last_action_id != tsk_fsm_state_none){ - if(tsip_dialog_invite_ice_got_local_candidates(dialog)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(dialog), dialog->ice.last_action_id, dialog->ice.last_message, dialog->ice.last_action); - dialog->ice.last_action_id = tsk_fsm_state_none; - } - } - if(dialog->ice.start_smgr){ - ret = tsip_dialog_invite_msession_start(dialog); - } - break; - } - // fatal errors which discard ICE process - case tnet_ice_event_type_gathering_host_candidates_failed: - case tnet_ice_event_type_gathering_reflexive_candidates_failed: - case tnet_ice_event_type_gathering_relay_candidates_failed: - { - if (dialog->ice.last_action_id != tsk_fsm_state_none) { + + switch(e->type) { + case tnet_ice_event_type_gathering_completed: + case tnet_ice_event_type_conncheck_succeed: + case tnet_ice_event_type_conncheck_failed: + case tnet_ice_event_type_cancelled: { + if(dialog->ice.last_action_id != tsk_fsm_state_none) { + if(tsip_dialog_invite_ice_got_local_candidates(dialog)) { ret = tsip_dialog_fsm_act(TSIP_DIALOG(dialog), dialog->ice.last_action_id, dialog->ice.last_message, dialog->ice.last_action); dialog->ice.last_action_id = tsk_fsm_state_none; } - break; } - // TURN session disconnected while we're in call - case tnet_ice_event_type_turn_connection_broken: - { - ret = tsip_dialog_fsm_act_2(TSIP_DIALOG(dialog), _fsm_action_oBYE); - break; + if(dialog->ice.start_smgr) { + ret = tsip_dialog_invite_msession_start(dialog); } - default: break; + break; } - + // fatal errors which discard ICE process + case tnet_ice_event_type_gathering_host_candidates_failed: + case tnet_ice_event_type_gathering_reflexive_candidates_failed: + case tnet_ice_event_type_gathering_relay_candidates_failed: { + if (dialog->ice.last_action_id != tsk_fsm_state_none) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(dialog), dialog->ice.last_action_id, dialog->ice.last_message, dialog->ice.last_action); + dialog->ice.last_action_id = tsk_fsm_state_none; + } + break; + } + // TURN session disconnected while we're in call + case tnet_ice_event_type_turn_connection_broken: { + ret = tsip_dialog_fsm_act_2(TSIP_DIALOG(dialog), _fsm_action_oBYE); + break; + } + default: + break; + } + TSK_OBJECT_SAFE_FREE(dialog); - + return ret; } diff --git a/tinySIP/src/dialogs/tsip_dialog_invite.qos.c b/tinySIP/src/dialogs/tsip_dialog_invite.qos.c index 8cc7a2a..4edf0f3 100755 --- a/tinySIP/src/dialogs/tsip_dialog_invite.qos.c +++ b/tinySIP/src/dialogs/tsip_dialog_invite.qos.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. * @@ -46,15 +46,15 @@ static int x0300_Any_2_Any_X_timerRSVP(va_list *app); /* Init FSM */ int tsip_dialog_invite_qos_init(tsip_dialog_invite_t *self) { - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + // Any -> (timerRSVP) -> Any + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_timerRSVP, tsk_fsm_state_any, x0300_Any_2_Any_X_timerRSVP, "x0300_Any_2_Any_X_timerRSVP"), - // Any -> (timerRSVP) -> Any - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_timerRSVP, tsk_fsm_state_any, x0300_Any_2_Any_X_timerRSVP, "x0300_Any_2_Any_X_timerRSVP"), - - TSK_FSM_ADD_NULL()); + TSK_FSM_ADD_NULL()); - return 0; + return 0; } //-------------------------------------------------------- @@ -64,8 +64,8 @@ int tsip_dialog_invite_qos_init(tsip_dialog_invite_t *self) // Any -> (tiner RSVP) -> Any int x0300_Any_2_Any_X_timerRSVP(va_list *app) { - tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); - return send_UPDATE(self, tsk_true); + tsip_dialog_invite_t *self = va_arg(*app, tsip_dialog_invite_t *); + return send_UPDATE(self, tsk_true); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -78,15 +78,15 @@ int x0300_Any_2_Any_X_timerRSVP(va_list *app) /* cancel the timer */ int tsip_dialog_invite_qos_timer_cancel(tsip_dialog_invite_t* self) { - return tsk_timer_mgr_global_cancel(self->qos.timer.id); + return tsk_timer_mgr_global_cancel(self->qos.timer.id); } /* schedule the timer */ int tsip_dialog_invite_qos_timer_schedule(tsip_dialog_invite_t* self) { - /* To emulate bandwidth reservation (Because RSVP protocol is not supported) */ - self->qos.timer.id = tsk_timer_mgr_global_schedule(TSIP_DIALOG_INVITE_QOS_RES_TIMEOUT, TSK_TIMER_CALLBACK_F(tsip_dialog_invite_timer_callback), self); + /* To emulate bandwidth reservation (Because RSVP protocol is not supported) */ + self->qos.timer.id = tsk_timer_mgr_global_schedule(TSIP_DIALOG_INVITE_QOS_RES_TIMEOUT, TSK_TIMER_CALLBACK_F(tsip_dialog_invite_timer_callback), self); - return 0; + return 0; } 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; } 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; } diff --git a/tinySIP/src/dialogs/tsip_dialog_layer.c b/tinySIP/src/dialogs/tsip_dialog_layer.c index 9a33fd3..f91dd33 100755 --- a/tinySIP/src/dialogs/tsip_dialog_layer.c +++ b/tinySIP/src/dialogs/tsip_dialog_layer.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 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. * @@ -47,281 +47,281 @@ extern tsip_ssession_handle_t *tsip_ssession_create_2(const tsip_stack_t* stack, /*== Predicate function to find dialog by type */ static int pred_find_dialog_by_type(const tsk_list_item_t *item, const void *type) { - if(item && item->data){ - tsip_dialog_t *dialog = item->data; - return (dialog->type - *((tsip_dialog_type_t*)type)); - } - return -1; + if(item && item->data) { + tsip_dialog_t *dialog = item->data; + return (dialog->type - *((tsip_dialog_type_t*)type)); + } + return -1; } /*== Predicate function to find dialog by not type */ static int pred_find_dialog_by_not_type(const tsk_list_item_t *item, const void *type) { - if(item && item->data){ - tsip_dialog_t *dialog = item->data; - if(dialog->type != *((tsip_dialog_type_t*)type)){ - return 0; - } - } - return -1; + if(item && item->data) { + tsip_dialog_t *dialog = item->data; + if(dialog->type != *((tsip_dialog_type_t*)type)) { + return 0; + } + } + return -1; } /*== Predicate function to find dialog by callid */ static int pred_find_dialog_by_callid(const tsk_list_item_t *item, const void *callid) { - if(item && item->data && callid){ - return tsk_strcmp(((tsip_dialog_t*)item->data)->callid, ((const char*)callid)); - } - return -1; + if(item && item->data && callid) { + return tsk_strcmp(((tsip_dialog_t*)item->data)->callid, ((const char*)callid)); + } + return -1; } tsip_dialog_layer_t* tsip_dialog_layer_create(tsip_stack_t* stack) { - return tsk_object_new(tsip_dialog_layer_def_t, stack); + return tsk_object_new(tsip_dialog_layer_def_t, stack); } // it's up to the caller to release the returned object tsip_dialog_t* tsip_dialog_layer_find_by_ss(tsip_dialog_layer_t *self, const tsip_ssession_handle_t *ss) { - return tsip_dialog_layer_find_by_ssid(self, tsip_ssession_get_id(ss)); + return tsip_dialog_layer_find_by_ssid(self, tsip_ssession_get_id(ss)); } // it's up to the caller to release the returned object tsip_dialog_t* tsip_dialog_layer_find_by_ssid(tsip_dialog_layer_t *self, tsip_ssession_id_t ssid) { - tsip_dialog_t *ret = 0; - tsip_dialog_t *dialog; - tsk_list_item_t *item; + tsip_dialog_t *ret = 0; + tsip_dialog_t *dialog; + tsk_list_item_t *item; - tsk_safeobj_lock(self); + tsk_safeobj_lock(self); - tsk_list_foreach(item, self->dialogs){ - dialog = item->data; - if(tsip_ssession_get_id(dialog->ss) == ssid){ - ret = dialog; - break; - } - } + tsk_list_foreach(item, self->dialogs) { + dialog = item->data; + if(tsip_ssession_get_id(dialog->ss) == ssid) { + ret = dialog; + break; + } + } - tsk_safeobj_unlock(self); + tsk_safeobj_unlock(self); - return tsk_object_ref(ret); + return tsk_object_ref(ret); } // it's up to the caller to release the returned object tsip_dialog_t* tsip_dialog_layer_find_by_callid(tsip_dialog_layer_t *self, const char* callid) { - if(!self || !callid){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - else{ - tsip_dialog_t *dialog = tsk_null; - tsk_list_item_t *item; - //--tsk_safeobj_lock(self); - tsk_list_foreach(item, self->dialogs){ - if(tsk_striequals(TSIP_DIALOG(item->data)->callid, callid)){ - dialog = tsk_object_ref(item->data); - break; - } - } - //--tsk_safeobj_unlock(self); - return dialog; - } + if(!self || !callid) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + else { + tsip_dialog_t *dialog = tsk_null; + tsk_list_item_t *item; + //--tsk_safeobj_lock(self); + tsk_list_foreach(item, self->dialogs) { + if(tsk_striequals(TSIP_DIALOG(item->data)->callid, callid)) { + dialog = tsk_object_ref(item->data); + break; + } + } + //--tsk_safeobj_unlock(self); + return dialog; + } } tsk_bool_t tsip_dialog_layer_have_dialog_with_callid(const tsip_dialog_layer_t *self, const char* callid) { - tsk_bool_t found = tsk_false; - if(self){ - tsk_safeobj_lock(self); - if(tsk_list_find_item_by_pred(self->dialogs, pred_find_dialog_by_callid, callid) != tsk_null){ - found = tsk_true; - } - tsk_safeobj_unlock(self); - } - return found; + tsk_bool_t found = tsk_false; + if(self) { + tsk_safeobj_lock(self); + if(tsk_list_find_item_by_pred(self->dialogs, pred_find_dialog_by_callid, callid) != tsk_null) { + found = tsk_true; + } + tsk_safeobj_unlock(self); + } + return found; } // it's up to the caller to release the returned object tsip_dialog_t* tsip_dialog_layer_find(const tsip_dialog_layer_t *self, const char* callid, const char* to_tag, const char* from_tag, tsip_request_type_t type, tsk_bool_t *cid_matched) { - tsip_dialog_t *ret = tsk_null; - tsip_dialog_t *dialog; - tsk_list_item_t *item; - - *cid_matched = tsk_false; - - tsk_safeobj_lock(self); - - tsk_list_foreach(item, self->dialogs){ - dialog = item->data; - if(tsk_strequals(dialog->callid, callid)){ - tsk_bool_t is_cancel = (type == tsip_CANCEL); // Incoming CANCEL - tsk_bool_t is_register = (type == tsip_REGISTER); // Incoming REGISTER - tsk_bool_t is_notify = (type == tsip_NOTIFY); // Incoming NOTIFY - *cid_matched = tsk_true; - /* CANCEL Request will have the same local tag than the INVITE request - the remote tag could be null if the CANCEL request is received immediately after a 100 Trying - */ - if((is_cancel || tsk_strequals(dialog->tag_local, from_tag)) && (!dialog->tag_remote || tsk_strequals(dialog->tag_remote, to_tag))){ - ret = tsk_object_ref(dialog); - break; - } - /* REGISTER is dialogless which means that each reREGISTER or unREGISTER will have empty to tag */ - if(is_register /* Do not check tags */){ - ret = tsk_object_ref(dialog); - break; - } - /* NOTIFY could arrive before the 200 SUBSCRIBE => This is why we don't try to match both tags - - RFC 3265 - 3.1.4.4. Confirmation of Subscription Creation - Due to the potential for both out-of-order messages and forking, the - subscriber MUST be prepared to receive NOTIFY messages before the - SUBSCRIBE transaction has completed. - */ - if(is_notify /* Do not check tags */){ - ret = tsk_object_ref(dialog); - break; - } - } - } - - tsk_safeobj_unlock(self); - - return ret; + tsip_dialog_t *ret = tsk_null; + tsip_dialog_t *dialog; + tsk_list_item_t *item; + + *cid_matched = tsk_false; + + tsk_safeobj_lock(self); + + tsk_list_foreach(item, self->dialogs) { + dialog = item->data; + if(tsk_strequals(dialog->callid, callid)) { + tsk_bool_t is_cancel = (type == tsip_CANCEL); // Incoming CANCEL + tsk_bool_t is_register = (type == tsip_REGISTER); // Incoming REGISTER + tsk_bool_t is_notify = (type == tsip_NOTIFY); // Incoming NOTIFY + *cid_matched = tsk_true; + /* CANCEL Request will have the same local tag than the INVITE request + the remote tag could be null if the CANCEL request is received immediately after a 100 Trying + */ + if((is_cancel || tsk_strequals(dialog->tag_local, from_tag)) && (!dialog->tag_remote || tsk_strequals(dialog->tag_remote, to_tag))) { + ret = tsk_object_ref(dialog); + break; + } + /* REGISTER is dialogless which means that each reREGISTER or unREGISTER will have empty to tag */ + if(is_register /* Do not check tags */) { + ret = tsk_object_ref(dialog); + break; + } + /* NOTIFY could arrive before the 200 SUBSCRIBE => This is why we don't try to match both tags + + RFC 3265 - 3.1.4.4. Confirmation of Subscription Creation + Due to the potential for both out-of-order messages and forking, the + subscriber MUST be prepared to receive NOTIFY messages before the + SUBSCRIBE transaction has completed. + */ + if(is_notify /* Do not check tags */) { + ret = tsk_object_ref(dialog); + break; + } + } + } + + tsk_safeobj_unlock(self); + + return ret; } tsk_size_t tsip_dialog_layer_count_active_calls(tsip_dialog_layer_t *self) { - tsk_size_t count = 0; + tsk_size_t count = 0; - tsip_dialog_t *dialog; - tsk_list_item_t *item; + tsip_dialog_t *dialog; + tsk_list_item_t *item; - tsk_safeobj_lock(self); + tsk_safeobj_lock(self); - tsk_list_foreach(item, self->dialogs) { - if ((dialog = item->data) && dialog->type == tsip_dialog_INVITE && dialog->state != tsip_initial && dialog->state != tsip_terminated) { - ++count; - } - } + tsk_list_foreach(item, self->dialogs) { + if ((dialog = item->data) && dialog->type == tsip_dialog_INVITE && dialog->state != tsip_initial && dialog->state != tsip_terminated) { + ++count; + } + } - tsk_safeobj_unlock(self); + tsk_safeobj_unlock(self); - return count; + return count; } /** Hangup all dialogs starting by non-REGISTER */ int tsip_dialog_layer_shutdownAll(tsip_dialog_layer_t *self) { - if(self){ - tsk_bool_t wait = tsk_false; - tsk_list_item_t *item; - tsip_dialog_t *dialog; - tsip_dialog_type_t regtype = tsip_dialog_REGISTER; - - if(!self->shutdown.inprogress){ - self->shutdown.inprogress = tsk_true; - if (!self->shutdown.condwait) { - self->shutdown.condwait = tsk_condwait_create(); - } - } - - tsk_safeobj_lock(self); - if(tsk_list_count(self->dialogs, pred_find_dialog_by_not_type, ®type)){ - /* There are non-register dialogs ==> phase-1 */ - goto phase1; - } - else if(tsk_list_count(self->dialogs, pred_find_dialog_by_type, ®type)){ - /* There are one or more register dialogs ==> phase-2 */ - goto phase2; - } - else{ - tsk_safeobj_unlock(self); - goto done; - } + if(self) { + tsk_bool_t wait = tsk_false; + tsk_list_item_t *item; + tsip_dialog_t *dialog; + tsip_dialog_type_t regtype = tsip_dialog_REGISTER; + + if(!self->shutdown.inprogress) { + self->shutdown.inprogress = tsk_true; + if (!self->shutdown.condwait) { + self->shutdown.condwait = tsk_condwait_create(); + } + } + + tsk_safeobj_lock(self); + if(tsk_list_count(self->dialogs, pred_find_dialog_by_not_type, ®type)) { + /* There are non-register dialogs ==> phase-1 */ + goto phase1; + } + else if(tsk_list_count(self->dialogs, pred_find_dialog_by_type, ®type)) { + /* There are one or more register dialogs ==> phase-2 */ + goto phase2; + } + else { + tsk_safeobj_unlock(self); + goto done; + } phase1: - /* Phase 1 - shutdown all except register and silent_hangup */ - TSK_DEBUG_INFO("== Shutting down - Phase-1 started =="); + /* Phase 1 - shutdown all except register and silent_hangup */ + TSK_DEBUG_INFO("== Shutting down - Phase-1 started =="); phase1_loop: - tsk_list_foreach(item, self->dialogs){ - dialog = item->data; - if(dialog->type != tsip_dialog_REGISTER && !dialog->ss->silent_hangup){ - item = tsk_object_ref(item); - if(!tsip_dialog_shutdown(dialog, tsk_null)){ - wait = tsk_true; - } - - // if "tsip_dialog_shutdown()" remove the dialog, then - // "self->dialogs" will be unsafe - if(!(item = tsk_object_unref(item))){ - goto phase1_loop; - } - } - } - tsk_safeobj_unlock(self); - - /* wait until phase-1 is completed */ - if(wait){ - tsk_condwait_timedwait(self->shutdown.condwait, TSIP_DIALOG_SHUTDOWN_TIMEOUT); - } - - /* lock and goto phase2 */ - tsk_safeobj_lock(self); - wait = tsk_false; - goto phase2; + tsk_list_foreach(item, self->dialogs) { + dialog = item->data; + if(dialog->type != tsip_dialog_REGISTER && !dialog->ss->silent_hangup) { + item = tsk_object_ref(item); + if(!tsip_dialog_shutdown(dialog, tsk_null)) { + wait = tsk_true; + } + + // if "tsip_dialog_shutdown()" remove the dialog, then + // "self->dialogs" will be unsafe + if(!(item = tsk_object_unref(item))) { + goto phase1_loop; + } + } + } + tsk_safeobj_unlock(self); + + /* wait until phase-1 is completed */ + if(wait) { + tsk_condwait_timedwait(self->shutdown.condwait, TSIP_DIALOG_SHUTDOWN_TIMEOUT); + } + + /* lock and goto phase2 */ + tsk_safeobj_lock(self); + wait = tsk_false; + goto phase2; phase2: - /* Phase 2 - unregister */ - TSK_DEBUG_INFO("== Shutting down - Phase-2 started =="); - self->shutdown.phase2 = tsk_true; + /* Phase 2 - unregister */ + TSK_DEBUG_INFO("== Shutting down - Phase-2 started =="); + self->shutdown.phase2 = tsk_true; phase2_loop: - tsk_list_foreach(item, self->dialogs){ - dialog = item->data; - if(dialog->type == tsip_dialog_REGISTER){ - item = tsk_object_ref(item); - if(!tsip_dialog_shutdown(dialog, tsk_null)){ - wait = tsk_true; - } - // if "tsip_dialog_shutdown()" remove the dialog, then - // "self->dialogs" will be unsafe - if(!(item = tsk_object_unref(item))){ - goto phase2_loop; - } - } - } - tsk_safeobj_unlock(self); - - /* wait until phase-2 is completed */ - if(wait){ - tsk_condwait_timedwait(self->shutdown.condwait, TSIP_DIALOG_SHUTDOWN_TIMEOUT); - } - - - /* Phase 3 - silenthangup (dialogs will be terminated immediately) */ - TSK_DEBUG_INFO("== Shutting down - Phase-3 =="); + tsk_list_foreach(item, self->dialogs) { + dialog = item->data; + if(dialog->type == tsip_dialog_REGISTER) { + item = tsk_object_ref(item); + if(!tsip_dialog_shutdown(dialog, tsk_null)) { + wait = tsk_true; + } + // if "tsip_dialog_shutdown()" remove the dialog, then + // "self->dialogs" will be unsafe + if(!(item = tsk_object_unref(item))) { + goto phase2_loop; + } + } + } + tsk_safeobj_unlock(self); + + /* wait until phase-2 is completed */ + if(wait) { + tsk_condwait_timedwait(self->shutdown.condwait, TSIP_DIALOG_SHUTDOWN_TIMEOUT); + } + + + /* Phase 3 - silenthangup (dialogs will be terminated immediately) */ + TSK_DEBUG_INFO("== Shutting down - Phase-3 =="); phase3_loop: - tsk_list_foreach(item, self->dialogs){ - dialog = item->data; - if(dialog->ss->silent_hangup){ - item = tsk_object_ref(item); - tsip_dialog_shutdown(dialog, tsk_null); - - // if "tsip_dialog_shutdown()" remove the dialog, then - // "self->dialogs" will became unsafe while looping - if(!(item = tsk_object_unref(item))){ - goto phase3_loop; - } - } - } + tsk_list_foreach(item, self->dialogs) { + dialog = item->data; + if(dialog->ss->silent_hangup) { + item = tsk_object_ref(item); + tsip_dialog_shutdown(dialog, tsk_null); + + // if "tsip_dialog_shutdown()" remove the dialog, then + // "self->dialogs" will became unsafe while looping + if(!(item = tsk_object_unref(item))) { + goto phase3_loop; + } + } + } done: - TSK_DEBUG_INFO("== Shutting down - Terminated =="); - return 0; - } - return -1; + TSK_DEBUG_INFO("== Shutting down - Terminated =="); + return 0; + } + return -1; } static void* TSK_STDCALL _tsip_dialog_signal_transport_error_async(void* dialog) @@ -332,396 +332,387 @@ static void* TSK_STDCALL _tsip_dialog_signal_transport_error_async(void* dialog) int tsip_dialog_layer_signal_stack_disconnected(tsip_dialog_layer_t *self) { - tsk_list_item_t *item; + tsk_list_item_t *item; // use copy for lock-free code and faster code. also fix issue 172 (https://code.google.com/p/idoubs/issues/detail?id=172) tsip_dialogs_L_t *dialogs_copy; tsip_dialog_t *dialog; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(dialogs_copy = tsk_list_create())) { TSK_DEBUG_ERROR("Failed to create list"); - return -1; + return -1; } - tsk_safeobj_lock(self); + tsk_safeobj_lock(self); tsk_list_pushback_list(dialogs_copy, self->dialogs); tsk_safeobj_unlock(self); - - tsk_list_foreach(item, dialogs_copy){ - if((dialog = TSIP_DIALOG(item->data))){ + + tsk_list_foreach(item, dialogs_copy) { + if((dialog = TSIP_DIALOG(item->data))) { tsip_dialog_signal_transport_error(dialog); } } TSK_OBJECT_SAFE_FREE(dialogs_copy); - return 0; + return 0; } int tsip_dialog_layer_signal_peer_disconnected(tsip_dialog_layer_t *self, const struct tsip_transport_stream_peer_s* peer) { - tsip_dialog_t *dialog; - const tsk_list_item_t *item; - - if(!self || !peer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - + tsip_dialog_t *dialog; + const tsk_list_item_t *item; + + if(!self || !peer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + //!\ must not lock the entire layer - // tsk_safeobj_lock(self); + // tsk_safeobj_lock(self); - tsk_list_lock(peer->dialogs_cids); - tsk_list_foreach(item, peer->dialogs_cids){ - if((dialog = tsip_dialog_layer_find_by_callid(self, TSK_STRING_STR(item->data)))){ - tsip_dialog_signal_transport_error(dialog); - TSK_OBJECT_SAFE_FREE(dialog); - } - else{ - // To avoid this WARN, you should call tsip_dialog_layer_have_dialog_with_callid() before adding a callid to a peer - TSK_DEBUG_WARN("Stream peer holds call-id='%s' but the dialog layer doesn't know it", TSK_STRING_STR(item->data)); - } - } - tsk_list_unlock(peer->dialogs_cids); + tsk_list_lock(peer->dialogs_cids); + tsk_list_foreach(item, peer->dialogs_cids) { + if((dialog = tsip_dialog_layer_find_by_callid(self, TSK_STRING_STR(item->data)))) { + tsip_dialog_signal_transport_error(dialog); + TSK_OBJECT_SAFE_FREE(dialog); + } + else { + // To avoid this WARN, you should call tsip_dialog_layer_have_dialog_with_callid() before adding a callid to a peer + TSK_DEBUG_WARN("Stream peer holds call-id='%s' but the dialog layer doesn't know it", TSK_STRING_STR(item->data)); + } + } + tsk_list_unlock(peer->dialogs_cids); - // tsk_safeobj_unlock(self); + // tsk_safeobj_unlock(self); - return 0; + return 0; } int tsip_dialog_layer_remove_callid_from_stream_peers(tsip_dialog_layer_t *self, const char* callid) { - if(self){ - return tsip_transport_layer_remove_callid_from_stream_peers(self->stack->layer_transport, callid); - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; + if(self) { + return tsip_transport_layer_remove_callid_from_stream_peers(self->stack->layer_transport, callid); + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; } /* the caller of this function must unref() the returned object */ tsip_dialog_t* tsip_dialog_layer_new(tsip_dialog_layer_t *self, tsip_dialog_type_t type, const tsip_ssession_t *ss) { - tsip_dialog_t* ret = tsk_null; - tsip_dialog_t* dialog; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - goto bail; - } - - switch(type){ - case tsip_dialog_INVITE: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_invite_create(ss, tsk_null))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_MESSAGE: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_message_create(ss))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_INFO: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_info_create(ss))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_OPTIONS: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_options_create(ss))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_PUBLISH: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_publish_create(ss))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_REGISTER: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_register_create(ss, tsk_null))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - case tsip_dialog_SUBSCRIBE: - { - if((dialog = (tsip_dialog_t*)tsip_dialog_subscribe_create(ss))){ - ret = tsk_object_ref(dialog); - tsk_list_push_back_data(self->dialogs, (void**)&dialog); - } - break; - } - - default: - { - TSK_DEBUG_ERROR("Dialog type not supported."); - break; - } - } + tsip_dialog_t* ret = tsk_null; + tsip_dialog_t* dialog; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + goto bail; + } + + switch(type) { + case tsip_dialog_INVITE: { + if((dialog = (tsip_dialog_t*)tsip_dialog_invite_create(ss, tsk_null))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_MESSAGE: { + if((dialog = (tsip_dialog_t*)tsip_dialog_message_create(ss))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_INFO: { + if((dialog = (tsip_dialog_t*)tsip_dialog_info_create(ss))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_OPTIONS: { + if((dialog = (tsip_dialog_t*)tsip_dialog_options_create(ss))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_PUBLISH: { + if((dialog = (tsip_dialog_t*)tsip_dialog_publish_create(ss))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_REGISTER: { + if((dialog = (tsip_dialog_t*)tsip_dialog_register_create(ss, tsk_null))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + case tsip_dialog_SUBSCRIBE: { + if((dialog = (tsip_dialog_t*)tsip_dialog_subscribe_create(ss))) { + ret = tsk_object_ref(dialog); + tsk_list_push_back_data(self->dialogs, (void**)&dialog); + } + break; + } + + default: { + TSK_DEBUG_ERROR("Dialog type not supported."); + break; + } + } bail: - return ret; + return ret; } int tsip_dialog_layer_remove(tsip_dialog_layer_t *self, const tsip_dialog_t *dialog) { - if(dialog && self){ - tsip_dialog_type_t regtype = tsip_dialog_REGISTER; - tsk_safeobj_lock(self); - - /* remove the dialog */ - tsk_list_remove_item_by_data(self->dialogs, dialog); - - /* whether shutting down? */ - if(self->shutdown.inprogress){ - if(self->shutdown.phase2){ /* Phase 2 (all non-REGISTER and silent dialogs have been removed) */ - if(tsk_list_count(self->dialogs, pred_find_dialog_by_type, ®type) == 0){ - /* alert only if there is not REGISTER dialog (ignore silents) */ - TSK_DEBUG_INFO("== Shutting down - Phase-2 completed =="); - tsk_condwait_broadcast(self->shutdown.condwait); - } - } - else{ /* Phase 1 */ - if(tsk_list_count(self->dialogs, pred_find_dialog_by_not_type, ®type) == 0){ - /* alert only if all dialogs except REGISTER have been removed */ - TSK_DEBUG_INFO("== Shutting down - Phase-1 completed =="); - tsk_condwait_broadcast(self->shutdown.condwait); - } - } - } - - tsk_safeobj_unlock(self); - - return 0; - } - - return -1; + if(dialog && self) { + tsip_dialog_type_t regtype = tsip_dialog_REGISTER; + tsk_safeobj_lock(self); + + /* remove the dialog */ + tsk_list_remove_item_by_data(self->dialogs, dialog); + + /* whether shutting down? */ + if(self->shutdown.inprogress) { + if(self->shutdown.phase2) { /* Phase 2 (all non-REGISTER and silent dialogs have been removed) */ + if(tsk_list_count(self->dialogs, pred_find_dialog_by_type, ®type) == 0) { + /* alert only if there is not REGISTER dialog (ignore silents) */ + TSK_DEBUG_INFO("== Shutting down - Phase-2 completed =="); + tsk_condwait_broadcast(self->shutdown.condwait); + } + } + else { /* Phase 1 */ + if(tsk_list_count(self->dialogs, pred_find_dialog_by_not_type, ®type) == 0) { + /* alert only if all dialogs except REGISTER have been removed */ + TSK_DEBUG_INFO("== Shutting down - Phase-1 completed =="); + tsk_condwait_broadcast(self->shutdown.condwait); + } + } + } + + tsk_safeobj_unlock(self); + + return 0; + } + + return -1; } // this function is only called if no transaction match // for responses, the transaction will always match int tsip_dialog_layer_handle_incoming_msg(const tsip_dialog_layer_t *self, tsip_message_t* message) { - int ret = -1; - tsk_bool_t cid_matched; - tsip_dialog_t* dialog; - tsip_transac_t* transac = tsk_null; - const tsip_transac_layer_t *layer_transac = self->stack->layer_transac; - - if(!layer_transac){ - goto bail; - } - - //tsk_safeobj_lock(self); - dialog = tsip_dialog_layer_find(self, message->Call_ID->value, - TSIP_MESSAGE_IS_RESPONSE(message) ? message->To->tag : message->From->tag, - TSIP_MESSAGE_IS_RESPONSE(message) ? message->From->tag : message->To->tag, - TSIP_MESSAGE_IS_REQUEST(message) ? TSIP_MESSAGE_AS_REQUEST(message)->line.request.request_type : tsip_NONE, - &cid_matched); - //tsk_safeobj_unlock(self); - - if(dialog){ - if(TSIP_REQUEST_IS_CANCEL(message) || TSIP_REQUEST_IS_ACK(message)){ - ret = dialog->callback(dialog, tsip_dialog_i_msg, message); - tsk_object_unref(dialog); - goto bail; - } - else{ - static tsk_bool_t isCT = tsk_false; - tsip_transac_dst_t* dst = tsip_transac_dst_dialog_create(dialog); - transac = tsip_transac_layer_new( - layer_transac, - isCT, - message, - dst - ); - TSK_OBJECT_SAFE_FREE(dst); - TSK_OBJECT_SAFE_FREE(dialog); - } - } - else{ - /* MediaProxyMode : forward all non-INVITE messages */ - if(self->stack->network.mode == tsip_stack_mode_webrtc2sip){ - tsk_bool_t b2bua; - - if(TSIP_MESSAGE_IS_REQUEST(message)){ - // requests received over TCP/TLS/UDP must contain "ws-src-ip" and "ws-src-port" parameters - if(!TNET_SOCKET_TYPE_IS_WS(message->src_net_type) && !TNET_SOCKET_TYPE_IS_WSS(message->src_net_type)){ - const char* ws_src_ip = tsk_params_get_param_value(message->line.request.uri->params, "ws-src-ip"); - const tnet_port_t ws_src_port = (tnet_port_t)tsk_params_get_param_value_as_int(message->line.request.uri->params, "ws-src-port"); - if(!tsip_transport_layer_have_stream_peer_with_remote_ip(self->stack->layer_transport, ws_src_ip, ws_src_port)){ - if(!TSIP_REQUEST_IS_ACK(message)){ // ACK do not expect response + int ret = -1; + tsk_bool_t cid_matched; + tsip_dialog_t* dialog; + tsip_transac_t* transac = tsk_null; + const tsip_transac_layer_t *layer_transac = self->stack->layer_transac; + + if(!layer_transac) { + goto bail; + } + + //tsk_safeobj_lock(self); + dialog = tsip_dialog_layer_find(self, message->Call_ID->value, + TSIP_MESSAGE_IS_RESPONSE(message) ? message->To->tag : message->From->tag, + TSIP_MESSAGE_IS_RESPONSE(message) ? message->From->tag : message->To->tag, + TSIP_MESSAGE_IS_REQUEST(message) ? TSIP_MESSAGE_AS_REQUEST(message)->line.request.request_type : tsip_NONE, + &cid_matched); + //tsk_safeobj_unlock(self); + + if(dialog) { + if(TSIP_REQUEST_IS_CANCEL(message) || TSIP_REQUEST_IS_ACK(message)) { + ret = dialog->callback(dialog, tsip_dialog_i_msg, message); + tsk_object_unref(dialog); + goto bail; + } + else { + static tsk_bool_t isCT = tsk_false; + tsip_transac_dst_t* dst = tsip_transac_dst_dialog_create(dialog); + transac = tsip_transac_layer_new( + layer_transac, + isCT, + message, + dst + ); + TSK_OBJECT_SAFE_FREE(dst); + TSK_OBJECT_SAFE_FREE(dialog); + } + } + else { + /* MediaProxyMode : forward all non-INVITE messages */ + if(self->stack->network.mode == tsip_stack_mode_webrtc2sip) { + tsk_bool_t b2bua; + + if(TSIP_MESSAGE_IS_REQUEST(message)) { + // requests received over TCP/TLS/UDP must contain "ws-src-ip" and "ws-src-port" parameters + if(!TNET_SOCKET_TYPE_IS_WS(message->src_net_type) && !TNET_SOCKET_TYPE_IS_WSS(message->src_net_type)) { + const char* ws_src_ip = tsk_params_get_param_value(message->line.request.uri->params, "ws-src-ip"); + const tnet_port_t ws_src_port = (tnet_port_t)tsk_params_get_param_value_as_int(message->line.request.uri->params, "ws-src-port"); + if(!tsip_transport_layer_have_stream_peer_with_remote_ip(self->stack->layer_transport, ws_src_ip, ws_src_port)) { + if(!TSIP_REQUEST_IS_ACK(message)) { // ACK do not expect response #if 0 // code commented because when using mjserver, rejecting the forked INVITE terminate all dialogs: have to check if it's conform to RFC 3261 or not - tsip_response_t* response = tsip_response_new(488, "WebSocket Peer not connected", message); - ret = tsip_transport_layer_send(self->stack->layer_transport, "no-branch", response); - TSK_OBJECT_SAFE_FREE(response); - return ret; + tsip_response_t* response = tsip_response_new(488, "WebSocket Peer not connected", message); + ret = tsip_transport_layer_send(self->stack->layer_transport, "no-branch", response); + TSK_OBJECT_SAFE_FREE(response); + return ret; #else - TSK_DEBUG_INFO("Request for peer at %s:%d cannot be delivered", ws_src_ip, ws_src_port); + TSK_DEBUG_INFO("Request for peer at %s:%d cannot be delivered", ws_src_ip, ws_src_port); #endif - } - return 0; - } - } - } - - // "rtcweb-breaker" parameter will be in the Contact header for outgoing request and in the request-uri for incoming requests - b2bua = TSIP_REQUEST_IS_INVITE(message) && message->Contact && message->Contact->uri && - (tsk_striequals(tsk_params_get_param_value(message->Contact->uri->params, "rtcweb-breaker"), "yes") - || tsk_striequals(tsk_params_get_param_value(message->line.request.uri->params, "rtcweb-breaker"), "yes")); - - if(!b2bua){ - // forward the message - static tsk_bool_t isCT = tsk_true; - tsip_transac_dst_t* dst; - tsip_transac_t* transac; - - TSIP_MESSAGE(message)->update = tsk_true; // update AoR and Via - if((dst = tsip_transac_dst_net_create(TSIP_STACK(self->stack)))){ - if((transac = tsip_transac_layer_new(self->stack->layer_transac, isCT, message, dst))){ - ret = tsip_transac_start(transac, message); - TSK_OBJECT_SAFE_FREE(transac); - } - TSK_OBJECT_SAFE_FREE(dst); - } - return ret; - } - } - - if(TSIP_MESSAGE_IS_REQUEST(message)){ - tsip_ssession_t* ss = tsk_null; - tsip_dialog_t* newdialog = tsk_null; - - switch(message->line.request.request_type){ - case tsip_MESSAGE: - { /* Server incoming MESSAGE */ - if((ss = tsip_ssession_create_2(self->stack, message))){ - newdialog = (tsip_dialog_t*)tsip_dialog_message_create(ss); - } - break; - } - case tsip_INFO: - { /* Server incoming INFO */ - if((ss = tsip_ssession_create_2(self->stack, message))){ - newdialog = (tsip_dialog_t*)tsip_dialog_info_create(ss); - } - break; - } - case tsip_OPTIONS: - { /* Server incoming OPTIONS */ - if((ss = tsip_ssession_create_2(self->stack, message))){ - newdialog = (tsip_dialog_t*)tsip_dialog_options_create(ss); - } - break; - } - - case tsip_REGISTER: - { /* incoming REGISTER */ - if((ss = tsip_ssession_create_2(self->stack, message))){ - newdialog = (tsip_dialog_t*)tsip_dialog_register_create(ss, message->Call_ID ? message->Call_ID->value : tsk_null); - } - break; - } - - case tsip_INVITE: - { /* incoming INVITE */ - if((ss = tsip_ssession_create_2(self->stack, message))){ - newdialog = (tsip_dialog_t*)tsip_dialog_invite_create(ss, message->Call_ID ? message->Call_ID->value : tsk_null); - } - break; - } - - default: - { - break; - } - }//switch - - // for new dialog, create a new transac and start it later - if(newdialog){ - static const tsk_bool_t isCT = tsk_false; - tsip_transac_dst_t* dst = tsip_transac_dst_dialog_create(newdialog); - transac = tsip_transac_layer_new( - layer_transac, - isCT, - message, - dst - ); - if(message->local_fd > 0 && TNET_SOCKET_TYPE_IS_STREAM(message->src_net_type)) { - tsip_dialog_set_connected_fd(newdialog, message->local_fd); - } - tsk_list_push_back_data(self->dialogs, (void**)&newdialog); /* add new dialog to the layer */ - TSK_OBJECT_SAFE_FREE(dst); - } - - /* The dialog will become the owner of the SIP session - * => when destoyed => SIP session will be destroyed, unless the user-end takes ownership() */ - TSK_OBJECT_SAFE_FREE(ss); - } - } - - if(transac){ - ret = tsip_transac_start(transac, message); - tsk_object_unref(transac); - } - /* - No transaction match for the SIP request - - ACK do not expect any response (http://code.google.com/p/imsdroid/issues/detail?id=420) - */ - else if(TSIP_MESSAGE_IS_REQUEST(message) && !TSIP_REQUEST_IS_ACK(message)){ - const tsip_transport_layer_t *layer; - tsip_response_t* response = tsk_null; - if(!dialog && cid_matched){ - dialog = tsip_dialog_layer_find_by_callid((tsip_dialog_layer_t *)self, message->Call_ID->value); - } - - if((layer = self->stack->layer_transport)){ - if(cid_matched){ /* We are receiving our own message. */ - response = tsip_response_new(482, "Loop Detected (Check your iFCs)", message); - if(response && !response->To->tag){/* Early dialog? */ - response->To->tag = tsk_strdup("doubango"); - } - } - else{ - switch(message->line.request.request_type){ - case tsip_OPTIONS: // Hacked to work on Tiscali IMS networks - case tsip_INFO: - response = tsip_response_new(405, "Method Not Allowed", message); - break; - default: - response = tsip_response_new(481, "Dialog/Transaction Does Not Exist", message); - break; - } - } - if(response){ - if(dialog && TSIP_DIALOG_GET_SS(dialog)){ - tsk_strupdate(&response->sigcomp_id, TSIP_DIALOG_GET_SS(dialog)->sigcomp_id); - } - ret = tsip_transport_layer_send(layer, response->firstVia ? response->firstVia->branch : "no-branch", response); - TSK_OBJECT_SAFE_FREE(response); - } - } - - TSK_OBJECT_SAFE_FREE(dialog); - } - + } + return 0; + } + } + } + + // "rtcweb-breaker" parameter will be in the Contact header for outgoing request and in the request-uri for incoming requests + b2bua = TSIP_REQUEST_IS_INVITE(message) && message->Contact && message->Contact->uri && + (tsk_striequals(tsk_params_get_param_value(message->Contact->uri->params, "rtcweb-breaker"), "yes") + || tsk_striequals(tsk_params_get_param_value(message->line.request.uri->params, "rtcweb-breaker"), "yes")); + + if(!b2bua) { + // forward the message + static tsk_bool_t isCT = tsk_true; + tsip_transac_dst_t* dst; + tsip_transac_t* transac; + + TSIP_MESSAGE(message)->update = tsk_true; // update AoR and Via + if((dst = tsip_transac_dst_net_create(TSIP_STACK(self->stack)))) { + if((transac = tsip_transac_layer_new(self->stack->layer_transac, isCT, message, dst))) { + ret = tsip_transac_start(transac, message); + TSK_OBJECT_SAFE_FREE(transac); + } + TSK_OBJECT_SAFE_FREE(dst); + } + return ret; + } + } + + if(TSIP_MESSAGE_IS_REQUEST(message)) { + tsip_ssession_t* ss = tsk_null; + tsip_dialog_t* newdialog = tsk_null; + + switch(message->line.request.request_type) { + case tsip_MESSAGE: { + /* Server incoming MESSAGE */ + if((ss = tsip_ssession_create_2(self->stack, message))) { + newdialog = (tsip_dialog_t*)tsip_dialog_message_create(ss); + } + break; + } + case tsip_INFO: { + /* Server incoming INFO */ + if((ss = tsip_ssession_create_2(self->stack, message))) { + newdialog = (tsip_dialog_t*)tsip_dialog_info_create(ss); + } + break; + } + case tsip_OPTIONS: { + /* Server incoming OPTIONS */ + if((ss = tsip_ssession_create_2(self->stack, message))) { + newdialog = (tsip_dialog_t*)tsip_dialog_options_create(ss); + } + break; + } + + case tsip_REGISTER: { + /* incoming REGISTER */ + if((ss = tsip_ssession_create_2(self->stack, message))) { + newdialog = (tsip_dialog_t*)tsip_dialog_register_create(ss, message->Call_ID ? message->Call_ID->value : tsk_null); + } + break; + } + + case tsip_INVITE: { + /* incoming INVITE */ + if((ss = tsip_ssession_create_2(self->stack, message))) { + newdialog = (tsip_dialog_t*)tsip_dialog_invite_create(ss, message->Call_ID ? message->Call_ID->value : tsk_null); + } + break; + } + + default: { + break; + } + }//switch + + // for new dialog, create a new transac and start it later + if(newdialog) { + static const tsk_bool_t isCT = tsk_false; + tsip_transac_dst_t* dst = tsip_transac_dst_dialog_create(newdialog); + transac = tsip_transac_layer_new( + layer_transac, + isCT, + message, + dst + ); + if(message->local_fd > 0 && TNET_SOCKET_TYPE_IS_STREAM(message->src_net_type)) { + tsip_dialog_set_connected_fd(newdialog, message->local_fd); + } + tsk_list_push_back_data(self->dialogs, (void**)&newdialog); /* add new dialog to the layer */ + TSK_OBJECT_SAFE_FREE(dst); + } + + /* The dialog will become the owner of the SIP session + * => when destoyed => SIP session will be destroyed, unless the user-end takes ownership() */ + TSK_OBJECT_SAFE_FREE(ss); + } + } + + if(transac) { + ret = tsip_transac_start(transac, message); + tsk_object_unref(transac); + } + /* - No transaction match for the SIP request + - ACK do not expect any response (http://code.google.com/p/imsdroid/issues/detail?id=420) + */ + else if(TSIP_MESSAGE_IS_REQUEST(message) && !TSIP_REQUEST_IS_ACK(message)) { + const tsip_transport_layer_t *layer; + tsip_response_t* response = tsk_null; + if(!dialog && cid_matched) { + dialog = tsip_dialog_layer_find_by_callid((tsip_dialog_layer_t *)self, message->Call_ID->value); + } + + if((layer = self->stack->layer_transport)) { + if(cid_matched) { /* We are receiving our own message. */ + response = tsip_response_new(482, "Loop Detected (Check your iFCs)", message); + if(response && !response->To->tag) { /* Early dialog? */ + response->To->tag = tsk_strdup("doubango"); + } + } + else { + switch(message->line.request.request_type) { + case tsip_OPTIONS: // Hacked to work on Tiscali IMS networks + case tsip_INFO: + response = tsip_response_new(405, "Method Not Allowed", message); + break; + default: + response = tsip_response_new(481, "Dialog/Transaction Does Not Exist", message); + break; + } + } + if(response) { + if(dialog && TSIP_DIALOG_GET_SS(dialog)) { + tsk_strupdate(&response->sigcomp_id, TSIP_DIALOG_GET_SS(dialog)->sigcomp_id); + } + ret = tsip_transport_layer_send(layer, response->firstVia ? response->firstVia->branch : "no-branch", response); + TSK_OBJECT_SAFE_FREE(response); + } + } + + TSK_OBJECT_SAFE_FREE(dialog); + } + bail: - return ret; + return ret; } @@ -733,44 +724,43 @@ bail: // static tsk_object_t* tsip_dialog_layer_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_layer_t *layer = self; - if(layer){ - layer->stack = va_arg(*app, const tsip_stack_t *); - layer->dialogs = tsk_list_create(); - - tsk_safeobj_init(layer); - } - return self; + tsip_dialog_layer_t *layer = self; + if(layer) { + layer->stack = va_arg(*app, const tsip_stack_t *); + layer->dialogs = tsk_list_create(); + + tsk_safeobj_init(layer); + } + return self; } static tsk_object_t* tsip_dialog_layer_dtor(tsk_object_t * self) -{ - tsip_dialog_layer_t *layer = self; - if(layer){ - TSK_OBJECT_SAFE_FREE(layer->dialogs); +{ + tsip_dialog_layer_t *layer = self; + if(layer) { + TSK_OBJECT_SAFE_FREE(layer->dialogs); - /* condwait */ - if(layer->shutdown.condwait){ - tsk_condwait_destroy(&layer->shutdown.condwait); - } + /* condwait */ + if(layer->shutdown.condwait) { + tsk_condwait_destroy(&layer->shutdown.condwait); + } - tsk_safeobj_deinit(layer); + tsk_safeobj_deinit(layer); - TSK_DEBUG_INFO("*** Dialog Layer destroyed ***"); - } - return self; + TSK_DEBUG_INFO("*** Dialog Layer destroyed ***"); + } + return self; } static int tsip_dialog_layer_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { - return -1; + return -1; } -static const tsk_object_def_t tsip_dialog_layer_def_s = -{ - sizeof(tsip_dialog_layer_t), - tsip_dialog_layer_ctor, - tsip_dialog_layer_dtor, - tsip_dialog_layer_cmp, +static const tsk_object_def_t tsip_dialog_layer_def_s = { + sizeof(tsip_dialog_layer_t), + tsip_dialog_layer_ctor, + tsip_dialog_layer_dtor, + tsip_dialog_layer_cmp, }; const tsk_object_def_t *tsip_dialog_layer_def_t = &tsip_dialog_layer_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_message.c b/tinySIP/src/dialogs/tsip_dialog_message.c index 9619eda..d3d4ad3 100755 --- a/tinySIP/src/dialogs/tsip_dialog_message.c +++ b/tinySIP/src/dialogs/tsip_dialog_message.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 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. * @@ -65,155 +65,150 @@ static int tsip_dialog_message_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ /* ======================== actions ======================== */ -typedef enum _fsm_action_e -{ - _fsm_action_sendMESSAGE = tsip_atype_message_send, - _fsm_action_accept = tsip_atype_accept, - _fsm_action_reject = tsip_atype_reject, - _fsm_action_cancel = tsip_atype_cancel, - _fsm_action_shutdown = tsip_atype_shutdown, - _fsm_action_transporterror = tsip_atype_transport_error, - - _fsm_action_receiveMESSAGE = 0xFF, - _fsm_action_1xx, - _fsm_action_2xx, - _fsm_action_401_407_421_494, - _fsm_action_300_to_699, - _fsm_action_error, +typedef enum _fsm_action_e { + _fsm_action_sendMESSAGE = tsip_atype_message_send, + _fsm_action_accept = tsip_atype_accept, + _fsm_action_reject = tsip_atype_reject, + _fsm_action_cancel = tsip_atype_cancel, + _fsm_action_shutdown = tsip_atype_shutdown, + _fsm_action_transporterror = tsip_atype_transport_error, + + _fsm_action_receiveMESSAGE = 0xFF, + _fsm_action_1xx, + _fsm_action_2xx, + _fsm_action_401_407_421_494, + _fsm_action_300_to_699, + _fsm_action_error, } _fsm_action_t; /* ======================== states ======================== */ -typedef enum _fsm_state_e -{ - _fsm_state_Started, - _fsm_state_Sending, - _fsm_state_Receiving, - _fsm_state_Terminated +typedef enum _fsm_state_e { + _fsm_state_Started, + _fsm_state_Sending, + _fsm_state_Receiving, + _fsm_state_Terminated } _fsm_state_t; static int tsip_dialog_message_event_callback(const tsip_dialog_message_t *self, tsip_dialog_event_type_t type, const tsip_message_t *msg) { - int ret = -1; - - switch(type) - { - case tsip_dialog_i_msg: - { - if(msg){ - if(TSIP_MESSAGE_IS_RESPONSE(msg)){ - const tsip_action_t* action = tsip_dialog_keep_action(TSIP_DIALOG(self), msg) ? TSIP_DIALOG(self)->curr_action : tsk_null; - if(TSIP_RESPONSE_IS_1XX(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, action); - } - else if(TSIP_RESPONSE_IS_2XX(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, action); - } - else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407 || TSIP_RESPONSE_CODE(msg) == 421 || TSIP_RESPONSE_CODE(msg) == 494){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); - } - else if(TSIP_RESPONSE_IS_3456(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_300_to_699, msg, action); - } - else{ /* Should never happen */ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); - } - } - else if (TSIP_REQUEST_IS_MESSAGE(msg)){ /* have been checked by dialog layer...but */ - // REQUEST ==> Incoming MESSAGE - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveMESSAGE, msg, tsk_null); - } - } - break; - } - - case tsip_dialog_canceled: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); - break; - } - - case tsip_dialog_terminated: - case tsip_dialog_timedout: - case tsip_dialog_error: - case tsip_dialog_transport_error: - { - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); - break; - } - - default: break; - } - - return ret; + int ret = -1; + + switch(type) { + case tsip_dialog_i_msg: { + if(msg) { + if(TSIP_MESSAGE_IS_RESPONSE(msg)) { + const tsip_action_t* action = tsip_dialog_keep_action(TSIP_DIALOG(self), msg) ? TSIP_DIALOG(self)->curr_action : tsk_null; + if(TSIP_RESPONSE_IS_1XX(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_1xx, msg, action); + } + else if(TSIP_RESPONSE_IS_2XX(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_2xx, msg, action); + } + else if(TSIP_RESPONSE_CODE(msg) == 401 || TSIP_RESPONSE_CODE(msg) == 407 || TSIP_RESPONSE_CODE(msg) == 421 || TSIP_RESPONSE_CODE(msg) == 494) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); + } + else if(TSIP_RESPONSE_IS_3456(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_300_to_699, msg, action); + } + else { /* Should never happen */ + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); + } + } + else if (TSIP_REQUEST_IS_MESSAGE(msg)) { /* have been checked by dialog layer...but */ + // REQUEST ==> Incoming MESSAGE + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveMESSAGE, msg, tsk_null); + } + } + break; + } + + case tsip_dialog_canceled: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_cancel, msg, tsk_null); + break; + } + + case tsip_dialog_terminated: + case tsip_dialog_timedout: + case tsip_dialog_error: + case tsip_dialog_transport_error: { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_transporterror, msg, tsk_null); + break; + } + + default: + break; + } + + return ret; } tsip_dialog_message_t* tsip_dialog_message_create(const tsip_ssession_handle_t* ss) { - return tsk_object_new(tsip_dialog_message_def_t, ss); + return tsk_object_new(tsip_dialog_message_def_t, ss); } int tsip_dialog_message_init(tsip_dialog_message_t *self) { - //const tsk_param_t* param; - - /* Initialize the state machine. */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (send) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_sendMESSAGE, _fsm_state_Sending, tsip_dialog_message_Started_2_Sending_X_sendMESSAGE, "tsip_dialog_message_Started_2_Sending_X_sendMESSAGE"), - // Started -> (receive) -> Receiving - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveMESSAGE, _fsm_state_Receiving, tsip_dialog_message_Started_2_Receiving_X_recvMESSAGE, "tsip_dialog_message_Started_2_Receiving_X_recvMESSAGE"), |