From 50dfb4359619563012997bc3ddafb7667741066c Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Tue, 23 Feb 2016 22:00:35 +0100 Subject: Add new QoS implementation Code formatting --- tinySIP/src/dialogs/tsip_dialog.c | 2239 ++++++++------- tinySIP/src/dialogs/tsip_dialog_info.c | 640 +++-- tinySIP/src/dialogs/tsip_dialog_invite.c | 2986 ++++++++++---------- tinySIP/src/dialogs/tsip_dialog_invite.client.c | 418 +-- tinySIP/src/dialogs/tsip_dialog_invite.ect.c | 594 ++-- tinySIP/src/dialogs/tsip_dialog_invite.hold.c | 306 +- tinySIP/src/dialogs/tsip_dialog_invite.ice.c | 326 ++- tinySIP/src/dialogs/tsip_dialog_invite.qos.c | 30 +- tinySIP/src/dialogs/tsip_dialog_invite.server.c | 1092 +++---- tinySIP/src/dialogs/tsip_dialog_invite.timers.c | 388 +-- tinySIP/src/dialogs/tsip_dialog_layer.c | 1156 ++++---- tinySIP/src/dialogs/tsip_dialog_message.c | 634 ++--- tinySIP/src/dialogs/tsip_dialog_options.c | 672 +++-- tinySIP/src/dialogs/tsip_dialog_publish.client.c | 821 +++--- tinySIP/src/dialogs/tsip_dialog_register.c | 627 ++-- tinySIP/src/dialogs/tsip_dialog_register.client.c | 524 ++-- tinySIP/src/dialogs/tsip_dialog_register.server.c | 252 +- tinySIP/src/dialogs/tsip_dialog_subscribe.client.c | 818 +++--- 18 files changed, 7228 insertions(+), 7295 deletions(-) (limited to 'tinySIP/src/dialogs') 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 -* +* * 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: - - ,,, - */ - 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: + + ,,, + */ + 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 -* +* * 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 -* +* * 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 = - "\r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " \r\n" - " %llu\r\n" - " \r\n" - " \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 = + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " %llu\r\n" + " \r\n" + " \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 -* +* * 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 -* +* * 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 -* +* * 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 @@ -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 -* +* * 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 -* +* * 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 && jvalue, 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 && jvalue, 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 -* +* * 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 -* +* * 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 -* +* * 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"), - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_message_Started_2_Started_X_any"), - - - /*======================= - * === Sending === - */ - // Sending -> (1xx) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_message_Sending_2_Sending_X_1xx, "tsip_dialog_message_Sending_2_Sending_X_1xx"), - // Sending -> (2xx) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_message_Sending_2_Terminated_X_2xx, "tsip_dialog_message_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_message_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_message_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_message_Sending_2_Terminated_X_300_to_699, "tsip_dialog_message_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_message_Sending_2_Terminated_X_cancel, "tsip_dialog_message_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_message_Sending_2_Terminated_X_shutdown"), - // Sending -> (Any) -> Sending - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_message_Sending_2_Sending_X_any"), - - /*======================= - * === Receiving === - */ - // Receiving -> (accept) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_accept, "tsip_dialog_message_Receiving_2_Terminated_X_accept"), - // Receiving -> (rejected) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_reject, "tsip_dialog_message_Receiving_2_Terminated_X_reject"), - // Receiving -> (Any) -> Receiving - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_message_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_message_Any_2_Terminated_X_transportError, "tsip_dialog_message_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_message_Any_2_Terminated_X_Error, "tsip_dialog_message_Any_2_Terminated_X_Error"), - - TSK_FSM_ADD_NULL()); - - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_message_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_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"), + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_message_Started_2_Started_X_any"), + + + /*======================= + * === Sending === + */ + // Sending -> (1xx) -> Sending + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_message_Sending_2_Sending_X_1xx, "tsip_dialog_message_Sending_2_Sending_X_1xx"), + // Sending -> (2xx) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_message_Sending_2_Terminated_X_2xx, "tsip_dialog_message_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_message_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_message_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_message_Sending_2_Terminated_X_300_to_699, "tsip_dialog_message_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_message_Sending_2_Terminated_X_cancel, "tsip_dialog_message_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_message_Sending_2_Terminated_X_shutdown"), + // Sending -> (Any) -> Sending + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_message_Sending_2_Sending_X_any"), + + /*======================= + * === Receiving === + */ + // Receiving -> (accept) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_accept, "tsip_dialog_message_Receiving_2_Terminated_X_accept"), + // Receiving -> (rejected) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_message_Receiving_2_Terminated_X_reject, "tsip_dialog_message_Receiving_2_Terminated_X_reject"), + // Receiving -> (Any) -> Receiving + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_message_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_message_Any_2_Terminated_X_transportError, "tsip_dialog_message_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_message_Any_2_Terminated_X_Error, "tsip_dialog_message_Any_2_Terminated_X_Error"), + + TSK_FSM_ADD_NULL()); + + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_message_event_callback); + + return 0; } @@ -226,216 +221,216 @@ int tsip_dialog_message_init(tsip_dialog_message_t *self) */ int tsip_dialog_message_Started_2_Sending_X_sendMESSAGE(va_list *app) { - tsip_dialog_message_t *self; + tsip_dialog_message_t *self; - self = va_arg(*app, tsip_dialog_message_t *); + self = va_arg(*app, tsip_dialog_message_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - return send_MESSAGE(self); + return send_MESSAGE(self); } /* Started -> (recvMESSAGE) -> Receiving */ int tsip_dialog_message_Started_2_Receiving_X_recvMESSAGE(va_list *app) { - tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - - /* Alert the user. */ - TSIP_DIALOG_MESSAGE_SIGNAL(self, tsip_i_message, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - - /* Update last incoming MESSAGE */ - TSK_OBJECT_SAFE_FREE(self->request); - self->request = tsk_object_ref((void*)request); - - return 0; + tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + + /* Alert the user. */ + TSIP_DIALOG_MESSAGE_SIGNAL(self, tsip_i_message, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + + /* Update last incoming MESSAGE */ + TSK_OBJECT_SAFE_FREE(self->request); + self->request = tsk_object_ref((void*)request); + + return 0; } /* Sending -> (1xx) -> Sending */ int tsip_dialog_message_Sending_2_Sending_X_1xx(va_list *app) { - /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ - /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ + /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ + /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ - return 0; + return 0; } /* Sending -> (2xx) -> Sending */ int tsip_dialog_message_Sending_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_MESSAGE_SIGNAL(self, tsip_ao_message, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_MESSAGE_SIGNAL(self, tsip_ao_message, + 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_message_Sending_2_Sending_X_401_407_421_494(va_list *app) { - tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_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_MESSAGE_SIGNAL(self, tsip_ao_message, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - return send_MESSAGE(self); + tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_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_MESSAGE_SIGNAL(self, tsip_ao_message, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return ret; + } + + return send_MESSAGE(self); } /* Sending -> (300 to 699) -> Terminated */ int tsip_dialog_message_Sending_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_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_MESSAGE_SIGNAL(self, tsip_ao_message, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_MESSAGE_SIGNAL(self, tsip_ao_message, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Sending -> (cancel) -> Terminated */ int tsip_dialog_message_Sending_2_Terminated_X_cancel(va_list *app) { - tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *); - /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ + tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_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, "MESSAGE cancelled"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "MESSAGE cancelled"); - return 0; + return 0; } /* Receiving -> (accept) -> Terminated */ int tsip_dialog_message_Receiving_2_Terminated_X_accept(va_list *app) { - tsip_dialog_message_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_message_t *); - va_arg(*app, tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - if(!self->request){ - TSK_DEBUG_ERROR("There is non MESSAGE 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->request))){ - 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_message_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_message_t *); + va_arg(*app, tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + if(!self->request) { + TSK_DEBUG_ERROR("There is non MESSAGE 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->request))) { + 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_message_Receiving_2_Terminated_X_reject(va_list *app) { - tsip_dialog_message_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_message_t *); - va_arg(*app, tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); - - if(!self->request){ - TSK_DEBUG_ERROR("There is non MESSAGE 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->request))){ - 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_message_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_message_t *); + va_arg(*app, tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); + + if(!self->request) { + TSK_DEBUG_ERROR("There is non MESSAGE 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->request))) { + 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_message_Any_2_Terminated_X_transportError(va_list *app) { - /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } /* Any -> (error) -> Terminated */ int tsip_dialog_message_Any_2_Terminated_X_Error(va_list *app) { - /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_message_t *self = va_arg(*app, tsip_dialog_message_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -444,39 +439,39 @@ int tsip_dialog_message_Any_2_Terminated_X_Error(va_list *app) int send_MESSAGE(tsip_dialog_message_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), "MESSAGE"))){ - return -2; - } + if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "MESSAGE"))) { + 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_message_OnTerminated(tsip_dialog_message_t *self) { - TSK_DEBUG_INFO("=== MESSAGE Dialog terminated ==="); + TSK_DEBUG_INFO("=== MESSAGE 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)); } @@ -505,48 +500,47 @@ int tsip_dialog_message_OnTerminated(tsip_dialog_message_t *self) // static tsk_object_t* tsip_dialog_message_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_message_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + tsip_dialog_message_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_MESSAGE, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_MESSAGE, 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_message_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_message_OnTerminated), (const void*)dialog); - /* Initialize the class itself */ - tsip_dialog_message_init(self); - } - return self; + /* Initialize the class itself */ + tsip_dialog_message_init(self); + } + return self; } static tsk_object_t* tsip_dialog_message_dtor(tsk_object_t * self) -{ - tsip_dialog_message_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->request); - - TSK_DEBUG_INFO("*** MESSAGE Dialog destroyed ***"); - } - return self; +{ + tsip_dialog_message_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->request); + + TSK_DEBUG_INFO("*** MESSAGE Dialog destroyed ***"); + } + return self; } static int tsip_dialog_message_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_message_def_s = -{ - sizeof(tsip_dialog_message_t), - tsip_dialog_message_ctor, - tsip_dialog_message_dtor, - tsip_dialog_message_cmp, +static const tsk_object_def_t tsip_dialog_message_def_s = { + sizeof(tsip_dialog_message_t), + tsip_dialog_message_ctor, + tsip_dialog_message_dtor, + tsip_dialog_message_cmp, }; const tsk_object_def_t *tsip_dialog_message_def_t = &tsip_dialog_message_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_options.c b/tinySIP/src/dialogs/tsip_dialog_options.c index 135be69..b0a5dbc 100755 --- a/tinySIP/src/dialogs/tsip_dialog_options.c +++ b/tinySIP/src/dialogs/tsip_dialog_options.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -66,153 +66,148 @@ static int tsip_dialog_options_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ /* ======================== actions ======================== */ -typedef enum _fsm_action_e -{ - _fsm_action_sendOPTIONS = tsip_atype_options_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_receiveOPTIONS = 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_sendOPTIONS = tsip_atype_options_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_receiveOPTIONS = 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; int tsip_dialog_options_event_callback(const tsip_dialog_options_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_OPTIONS(msg)){ /* have been checked by dialog layer...but */ - // REQUEST ==> Incoming OPTIONS - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveOPTIONS, 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_OPTIONS(msg)) { /* have been checked by dialog layer...but */ + // REQUEST ==> Incoming OPTIONS + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_receiveOPTIONS, 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_options_t* tsip_dialog_options_create(const tsip_ssession_handle_t* ss) { - return tsk_object_new(tsip_dialog_options_def_t, ss); + return tsk_object_new(tsip_dialog_options_def_t, ss); } int tsip_dialog_options_init(tsip_dialog_options_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_sendOPTIONS, _fsm_state_Sending, tsip_dialog_options_Started_2_Sending_X_sendOPTIONS, "tsip_dialog_options_Started_2_Sending_X_sendOPTIONS"), - // Started -> (receive) -> Receiving - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveOPTIONS, _fsm_state_Receiving, tsip_dialog_options_Started_2_Receiving_X_recvOPTIONS, "tsip_dialog_options_Started_2_Receiving_X_recvOPTIONS"), - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_options_Started_2_Started_X_any"), - - - /*======================= - * === Sending === - */ - // Sending -> (1xx) -> Sending - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_options_Sending_2_Sending_X_1xx, "tsip_dialog_options_Sending_2_Sending_X_1xx"), - // Sending -> (2xx) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_options_Sending_2_Terminated_X_2xx, "tsip_dialog_options_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_options_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_options_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_options_Sending_2_Terminated_X_300_to_699, "tsip_dialog_options_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_options_Sending_2_Terminated_X_cancel, "tsip_dialog_options_Sending_2_Terminated_X_cancel"), - // Sending -> (Any) -> Sending - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_options_Sending_2_Sending_X_any"), - - /*======================= - * === Receiving === - */ - // Receiving -> (accept) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_options_Receiving_2_Terminated_X_accept, "tsip_dialog_options_Receiving_2_Terminated_X_accept"), - // Receiving -> (rejected) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_options_Receiving_2_Terminated_X_reject, "tsip_dialog_options_Receiving_2_Terminated_X_reject"), - // Receiving -> (Any) -> Receiving - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_options_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_options_Any_2_Terminated_X_transportError, "tsip_dialog_options_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_options_Any_2_Terminated_X_Error, "tsip_dialog_options_Any_2_Terminated_X_Error"), - - TSK_FSM_ADD_NULL()); - - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_options_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_sendOPTIONS, _fsm_state_Sending, tsip_dialog_options_Started_2_Sending_X_sendOPTIONS, "tsip_dialog_options_Started_2_Sending_X_sendOPTIONS"), + // Started -> (receive) -> Receiving + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_receiveOPTIONS, _fsm_state_Receiving, tsip_dialog_options_Started_2_Receiving_X_recvOPTIONS, "tsip_dialog_options_Started_2_Receiving_X_recvOPTIONS"), + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_options_Started_2_Started_X_any"), + + + /*======================= + * === Sending === + */ + // Sending -> (1xx) -> Sending + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_1xx, _fsm_state_Sending, tsip_dialog_options_Sending_2_Sending_X_1xx, "tsip_dialog_options_Sending_2_Sending_X_1xx"), + // Sending -> (2xx) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Sending, _fsm_action_2xx, _fsm_state_Terminated, tsip_dialog_options_Sending_2_Terminated_X_2xx, "tsip_dialog_options_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_options_Sending_2_Sending_X_401_407_421_494, "tsip_dialog_options_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_options_Sending_2_Terminated_X_300_to_699, "tsip_dialog_options_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_options_Sending_2_Terminated_X_cancel, "tsip_dialog_options_Sending_2_Terminated_X_cancel"), + // Sending -> (Any) -> Sending + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Sending, "tsip_dialog_options_Sending_2_Sending_X_any"), + + /*======================= + * === Receiving === + */ + // Receiving -> (accept) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_accept, _fsm_state_Terminated, tsip_dialog_options_Receiving_2_Terminated_X_accept, "tsip_dialog_options_Receiving_2_Terminated_X_accept"), + // Receiving -> (rejected) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Receiving, _fsm_action_reject, _fsm_state_Terminated, tsip_dialog_options_Receiving_2_Terminated_X_reject, "tsip_dialog_options_Receiving_2_Terminated_X_reject"), + // Receiving -> (Any) -> Receiving + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Receiving, "tsip_dialog_options_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_options_Any_2_Terminated_X_transportError, "tsip_dialog_options_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_options_Any_2_Terminated_X_Error, "tsip_dialog_options_Any_2_Terminated_X_Error"), + + TSK_FSM_ADD_NULL()); + + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_options_event_callback); + + return 0; } @@ -225,217 +220,217 @@ int tsip_dialog_options_init(tsip_dialog_options_t *self) */ int tsip_dialog_options_Started_2_Sending_X_sendOPTIONS(va_list *app) { - tsip_dialog_options_t *self; + tsip_dialog_options_t *self; - self = va_arg(*app, tsip_dialog_options_t *); + self = va_arg(*app, tsip_dialog_options_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - return send_OPTIONS(self); + return send_OPTIONS(self); } /* Started -> (recvOPTIONS) -> Receiving */ int tsip_dialog_options_Started_2_Receiving_X_recvOPTIONS(va_list *app) { - tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - /* Update last incoming MESSAGE */ - TSK_OBJECT_SAFE_FREE(self->last_iMessage); - self->last_iMessage = tsk_object_ref((void*)request); + /* Update last incoming MESSAGE */ + TSK_OBJECT_SAFE_FREE(self->last_iMessage); + self->last_iMessage = tsk_object_ref((void*)request); - /* Alert the user. */ - TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_i_options, - tsip_event_code_dialog_request_incoming, "Incoming Request.", request); + /* Alert the user. */ + TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_i_options, + tsip_event_code_dialog_request_incoming, "Incoming Request.", request); - return 0; + return 0; } /* Sending -> (1xx) -> Sending */ int tsip_dialog_options_Sending_2_Sending_X_1xx(va_list *app) { - /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ - /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ + /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ + /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ - return 0; + return 0; } /* Sending -> (2xx) -> Sending */ int tsip_dialog_options_Sending_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_ao_options, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_ao_options, + 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_options_Sending_2_Sending_X_401_407_421_494(va_list *app) { - tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_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_OPTIONS_SIGNAL(self, tsip_ao_options, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - return send_OPTIONS(self); + tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_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_OPTIONS_SIGNAL(self, tsip_ao_options, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return ret; + } + + return send_OPTIONS(self); } /* Sending -> (300 to 699) -> Terminated */ int tsip_dialog_options_Sending_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_ao_options, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_OPTIONS_SIGNAL(self, tsip_ao_options, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Sending -> (cancel) -> Terminated */ int tsip_dialog_options_Sending_2_Terminated_X_cancel(va_list *app) { - int ret; + int ret; - tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *); - /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ + tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_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)) */ - ret = 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)) */ + ret = tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "OPTIONS cancelled"); + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "OPTIONS cancelled"); - return ret; + return ret; } /* Receiving -> (accept) -> Terminated */ int tsip_dialog_options_Receiving_2_Terminated_X_accept(va_list *app) { - tsip_dialog_options_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_options_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 OPTIONS 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_options_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_options_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 OPTIONS 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_options_Receiving_2_Terminated_X_reject(va_list *app) { - tsip_dialog_options_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_options_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 OPTIONS 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_options_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_options_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 OPTIONS 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_options_Any_2_Terminated_X_transportError(va_list *app) { - /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } /* Any -> (error) -> Terminated */ int tsip_dialog_options_Any_2_Terminated_X_Error(va_list *app) { - /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + /*tsip_dialog_options_t *self = va_arg(*app, tsip_dialog_options_t *);*/ + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - return 0; + return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -444,64 +439,64 @@ int tsip_dialog_options_Any_2_Terminated_X_Error(va_list *app) int send_OPTIONS(tsip_dialog_options_t *self) { - tsip_request_t* request = tsk_null; - int ret = -1; - - if(!self){ - return -1; - } - - if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "OPTIONS"))){ - return -2; - } - - /* action parameters and payload*/ - if(TSIP_DIALOG(self)->curr_action){ - const tsk_list_item_t* item; - tsk_list_foreach(item, TSIP_DIALOG(self)->curr_action->headers){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); - } - if(TSIP_DIALOG(self)->curr_action->payload){ - tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(TSIP_DIALOG(self)->curr_action->payload), TSK_BUFFER_SIZE(TSIP_DIALOG(self)->curr_action->payload)); - } - } - - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - TSK_OBJECT_SAFE_FREE(request); - - return ret; + tsip_request_t* request = tsk_null; + int ret = -1; + + if(!self) { + return -1; + } + + if(!(request = tsip_dialog_request_new(TSIP_DIALOG(self), "OPTIONS"))) { + return -2; + } + + /* action parameters and payload*/ + if(TSIP_DIALOG(self)->curr_action) { + const tsk_list_item_t* item; + tsk_list_foreach(item, TSIP_DIALOG(self)->curr_action->headers) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); + } + if(TSIP_DIALOG(self)->curr_action->payload) { + tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(TSIP_DIALOG(self)->curr_action->payload), TSK_BUFFER_SIZE(TSIP_DIALOG(self)->curr_action->payload)); + } + } + + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + TSK_OBJECT_SAFE_FREE(request); + + return ret; } int send_response(tsip_dialog_options_t *self, short status, const char* phrase, const tsip_request_t *request) { - tsip_response_t *response; - int ret = -1; - - response = tsip_dialog_response_new(TSIP_DIALOG(self), status, phrase, request); - if(response){ - if(response->To && !response->To->tag){ - tsk_istr_t tag; - tsk_strrandom(&tag); - response->To->tag = tsk_strdup(tag); - } - ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - - return ret; + tsip_response_t *response; + int ret = -1; + + response = tsip_dialog_response_new(TSIP_DIALOG(self), status, phrase, request); + if(response) { + if(response->To && !response->To->tag) { + tsk_istr_t tag; + tsk_strrandom(&tag); + response->To->tag = tsk_strdup(tag); + } + ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + + return ret; } int tsip_dialog_options_OnTerminated(tsip_dialog_options_t *self) { - TSK_DEBUG_INFO("=== OPTIONS Dialog terminated ==="); + TSK_DEBUG_INFO("=== OPTIONS Dialog terminated ==="); - /* alert 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 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)); } @@ -530,49 +525,48 @@ int tsip_dialog_options_OnTerminated(tsip_dialog_options_t *self) // static tsk_object_t* tsip_dialog_options_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_options_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + tsip_dialog_options_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_OPTIONS, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_OPTIONS, 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_options_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_options_OnTerminated), (const void*)dialog); - /* Initialize the class itself */ - tsip_dialog_options_init(self); - } - return self; + /* Initialize the class itself */ + tsip_dialog_options_init(self); + } + return self; } static tsk_object_t* tsip_dialog_options_dtor(tsk_object_t * self) -{ - tsip_dialog_options_t *dialog = self; - if(dialog){ +{ + tsip_dialog_options_t *dialog = self; + if(dialog) { - /* DeInitialize base class (will cancel all transactions) */ - tsip_dialog_deinit(TSIP_DIALOG(self)); + /* DeInitialize base class (will cancel all transactions) */ + tsip_dialog_deinit(TSIP_DIALOG(self)); - /* DeInitialize self */ - TSK_OBJECT_SAFE_FREE(dialog->last_iMessage); + /* DeInitialize self */ + TSK_OBJECT_SAFE_FREE(dialog->last_iMessage); - TSK_DEBUG_INFO("*** OPTIONS Dialog destroyed ***"); - } - return self; + TSK_DEBUG_INFO("*** OPTIONS Dialog destroyed ***"); + } + return self; } static int tsip_dialog_options_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_options_def_s = -{ - sizeof(tsip_dialog_options_t), - tsip_dialog_options_ctor, - tsip_dialog_options_dtor, - tsip_dialog_options_cmp, +static const tsk_object_def_t tsip_dialog_options_def_s = { + sizeof(tsip_dialog_options_t), + tsip_dialog_options_ctor, + tsip_dialog_options_dtor, + tsip_dialog_options_cmp, }; const tsk_object_def_t *tsip_dialog_options_def_t = &tsip_dialog_options_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_publish.client.c b/tinySIP/src/dialogs/tsip_dialog_publish.client.c index aa22737..3534119 100755 --- a/tinySIP/src/dialogs/tsip_dialog_publish.client.c +++ b/tinySIP/src/dialogs/tsip_dialog_publish.client.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -71,51 +71,49 @@ static int tsip_dialog_publish_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_unpublishing(tsip_dialog_publish_t* dialog, tsip_message_t* message) { - return dialog->unpublishing; + return dialog->unpublishing; } static tsk_bool_t _fsm_cond_publishing(tsip_dialog_publish_t* dialog, tsip_message_t* message) { - return !_fsm_cond_unpublishing(dialog, message); + return !_fsm_cond_unpublishing(dialog, message); } static tsk_bool_t _fsm_cond_silent_hangup(tsip_dialog_publish_t* dialog, tsip_message_t* message) { - return TSIP_DIALOG(dialog)->ss->silent_hangup; + return TSIP_DIALOG(dialog)->ss->silent_hangup; } static tsk_bool_t _fsm_cond_not_silent_hangup(tsip_dialog_publish_t* dialog, tsip_message_t* message) { - return !TSIP_DIALOG(dialog)->ss->silent_hangup; + return !TSIP_DIALOG(dialog)->ss->silent_hangup; } #define _fsm_cond_silent_shutdown _fsm_cond_silent_hangup #define _fsm_cond_not_silent_shutdown _fsm_cond_not_silent_hangup /* ======================== actions ======================== */ -typedef enum _fsm_action_e -{ - _fsm_action_publish = tsip_atype_publish, - _fsm_action_cancel = tsip_atype_cancel, - _fsm_action_hangup = tsip_atype_unpublish, - _fsm_action_shutdown = tsip_atype_shutdown, - _fsm_action_transporterror = tsip_atype_transport_error, - - _fsm_action_1xx = 0xFF, - _fsm_action_2xx, - _fsm_action_401_407_421_494, - _fsm_action_423, - _fsm_action_300_to_699, - _fsm_action_shutdown_timedout, /* Any -> Terminated */ - _fsm_action_error, +typedef enum _fsm_action_e { + _fsm_action_publish = tsip_atype_publish, + _fsm_action_cancel = tsip_atype_cancel, + _fsm_action_hangup = tsip_atype_unpublish, + _fsm_action_shutdown = tsip_atype_shutdown, + _fsm_action_transporterror = tsip_atype_transport_error, + + _fsm_action_1xx = 0xFF, + _fsm_action_2xx, + _fsm_action_401_407_421_494, + _fsm_action_423, + _fsm_action_300_to_699, + _fsm_action_shutdown_timedout, /* Any -> Terminated */ + _fsm_action_error, } _fsm_action_t; /* ======================== states ======================== */ -typedef enum _fsm_state_e -{ - _fsm_state_Started, - _fsm_state_Trying, - _fsm_state_Connected, - _fsm_state_Terminated +typedef enum _fsm_state_e { + _fsm_state_Started, + _fsm_state_Trying, + _fsm_state_Connected, + _fsm_state_Terminated } _fsm_state_t; @@ -124,182 +122,178 @@ _fsm_state_t; * Callback function called to alert the dialog for new events from the transaction/transport layers. * * @param [in,out] self A reference to the dialog. - * @param type The event type. - * @param [in,out] msg The incoming SIP/IMS message. + * @param type The event type. + * @param [in,out] msg The incoming SIP/IMS message. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_publish_event_callback(const tsip_dialog_publish_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 && 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)){ - 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); - } - else if(TSIP_RESPONSE_IS(msg,423)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); - } - else{ - // Alert User - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); - /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ - } - } - else{ - // - // REQUEST - // - } - 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 && 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)) { + 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); + } + else if(TSIP_RESPONSE_IS(msg,423)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); + } + else { + // Alert User + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); + /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ + } + } + else { + // + // REQUEST + // + } + 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; } /** * Timer manager callback. * - * @param [in,out] self The owner of the signaled timer. + * @param [in,out] 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_publish_timer_callback(const tsip_dialog_publish_t* self, tsk_timer_id_t timer_id) { - int ret = -1; - - if(self) - { - if(timer_id == self->timerrefresh.id){ - tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_publish, tsk_null, tsk_null); - ret = 0; - } - else if(timer_id == self->timershutdown.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, tsk_null, tsk_null); - } - } - return ret; + int ret = -1; + + if(self) { + if(timer_id == self->timerrefresh.id) { + tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_publish, tsk_null, tsk_null); + ret = 0; + } + else if(timer_id == self->timershutdown.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, tsk_null, tsk_null); + } + } + return ret; } tsip_dialog_publish_t* tsip_dialog_publish_create(const tsip_ssession_handle_t* ss) { - return tsk_object_new(tsip_dialog_publish_def_t, ss); + return tsk_object_new(tsip_dialog_publish_def_t, ss); } /** * Initializes the dialog. * - * @param [in,out] self The dialog to initialize. + * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_publish_init(tsip_dialog_publish_t *self) -{ - /* Initialize the State Machine. */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (PUBLISH) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_publish, _fsm_state_Trying, tsip_dialog_publish_Started_2_Trying_X_publish, "tsip_dialog_publish_Started_2_Trying_X_publish"), - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_publish_Started_2_Started_X_any"), - - - /*======================= - * === Trying === - */ - // Trying -> (1xx) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_1xx, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_1xx, "tsip_dialog_publish_Trying_2_Trying_X_1xx"), - // Trying -> (2xx) -> Terminated - TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_unpublishing, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_2xx, "tsip_dialog_publish_Trying_2_Terminated_X_2xx"), - // Trying -> (2xx) -> Connected - TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_publishing, _fsm_state_Connected, tsip_dialog_publish_Trying_2_Connected_X_2xx, "tsip_dialog_publish_Trying_2_Connected_X_2xx"), - // Trying -> (401/407/421/494) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_401_407_421_494, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_401_407_421_494, "tsip_dialog_publish_Trying_2_Trying_X_401_407_421_494"), - // Trying -> (423) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_423, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_423, "tsip_dialog_publish_Trying_2_Trying_X_423"), - // Trying -> (300_to_699) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_300_to_699, "tsip_dialog_publish_Trying_2_Terminated_X_300_to_699"), - // Trying -> (cancel) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_cancel, "tsip_dialog_publish_Trying_2_Terminated_X_cancel"), - // Trying -> (hangup) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Trying_2_Terminated_X_hangup"), - // Trying -> (shutdown) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Trying_2_Terminated_X_shutdown"), - // Trying -> (Any) -> Trying - // TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Trying, "tsip_dialog_publish_Trying_2_Trying_X_any"), - - - /*======================= - * === Connected === - */ - // Connected -> (PUBLISH) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_publish, _fsm_state_Trying, tsip_dialog_publish_Connected_2_Trying_X_publish, "tsip_dialog_publish_Connected_2_Trying_X_publish"), - - /*======================= - * === Any === - */ - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_publish_Any_2_Terminated_X_transportError, "tsip_dialog_publish_Any_2_Terminated_X_transportError"), - // Any -> (error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_publish_Any_2_Terminated_X_Error, "tsip_dialog_publish_Any_2_Terminated_X_Error"), - // Any -> (hangup) -> Trying - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_Trying, tsip_dialog_publish_Any_2_Trying_X_hangup, "tsip_dialog_publish_Any_2_Trying_X_hangup"), - // Any -> (silenthangup) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Any_2_Trying_X_silenthangup"), - // Any -> (shutdown) -> Trying - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_Trying, tsip_dialog_publish_Any_2_Trying_X_shutdown, "tsip_dialog_publish_Any_2_Trying_X_shutdown"), - // Any -> (silentshutdown) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_publishe_Any_2_Trying_X_silentshutdown"), - // Any -> (shutdown timedout) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_shutdown_timedout"), - - TSK_FSM_ADD_NULL()); - - /* Sets callback function */ - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_publish_event_callback); - - /* Timers */ - self->timerrefresh.id = TSK_INVALID_TIMER_ID; - self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; - self->timershutdown.id = TSK_INVALID_TIMER_ID; - self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; - - return 0; +{ + /* Initialize the State Machine. */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (PUBLISH) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_publish, _fsm_state_Trying, tsip_dialog_publish_Started_2_Trying_X_publish, "tsip_dialog_publish_Started_2_Trying_X_publish"), + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_publish_Started_2_Started_X_any"), + + + /*======================= + * === Trying === + */ + // Trying -> (1xx) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_1xx, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_1xx, "tsip_dialog_publish_Trying_2_Trying_X_1xx"), + // Trying -> (2xx) -> Terminated + TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_unpublishing, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_2xx, "tsip_dialog_publish_Trying_2_Terminated_X_2xx"), + // Trying -> (2xx) -> Connected + TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_publishing, _fsm_state_Connected, tsip_dialog_publish_Trying_2_Connected_X_2xx, "tsip_dialog_publish_Trying_2_Connected_X_2xx"), + // Trying -> (401/407/421/494) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_401_407_421_494, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_401_407_421_494, "tsip_dialog_publish_Trying_2_Trying_X_401_407_421_494"), + // Trying -> (423) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_423, _fsm_state_Trying, tsip_dialog_publish_Trying_2_Trying_X_423, "tsip_dialog_publish_Trying_2_Trying_X_423"), + // Trying -> (300_to_699) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_300_to_699, "tsip_dialog_publish_Trying_2_Terminated_X_300_to_699"), + // Trying -> (cancel) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_publish_Trying_2_Terminated_X_cancel, "tsip_dialog_publish_Trying_2_Terminated_X_cancel"), + // Trying -> (hangup) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Trying_2_Terminated_X_hangup"), + // Trying -> (shutdown) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Trying_2_Terminated_X_shutdown"), + // Trying -> (Any) -> Trying + // TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Trying, "tsip_dialog_publish_Trying_2_Trying_X_any"), + + + /*======================= + * === Connected === + */ + // Connected -> (PUBLISH) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_publish, _fsm_state_Trying, tsip_dialog_publish_Connected_2_Trying_X_publish, "tsip_dialog_publish_Connected_2_Trying_X_publish"), + + /*======================= + * === Any === + */ + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_publish_Any_2_Terminated_X_transportError, "tsip_dialog_publish_Any_2_Terminated_X_transportError"), + // Any -> (error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_publish_Any_2_Terminated_X_Error, "tsip_dialog_publish_Any_2_Terminated_X_Error"), + // Any -> (hangup) -> Trying + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_Trying, tsip_dialog_publish_Any_2_Trying_X_hangup, "tsip_dialog_publish_Any_2_Trying_X_hangup"), + // Any -> (silenthangup) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_Any_2_Trying_X_silenthangup"), + // Any -> (shutdown) -> Trying + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_Trying, tsip_dialog_publish_Any_2_Trying_X_shutdown, "tsip_dialog_publish_Any_2_Trying_X_shutdown"), + // Any -> (silentshutdown) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_publishe_Any_2_Trying_X_silentshutdown"), + // Any -> (shutdown timedout) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_publish_shutdown_timedout"), + + TSK_FSM_ADD_NULL()); + + /* Sets callback function */ + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_publish_event_callback); + + /* Timers */ + self->timerrefresh.id = TSK_INVALID_TIMER_ID; + self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; + self->timershutdown.id = TSK_INVALID_TIMER_ID; + self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; + + return 0; } //-------------------------------------------------------- @@ -311,246 +305,246 @@ int tsip_dialog_publish_init(tsip_dialog_publish_t *self) */ int tsip_dialog_publish_Started_2_Trying_X_publish(va_list *app) { - tsip_dialog_publish_t *self; + tsip_dialog_publish_t *self; - self = va_arg(*app, tsip_dialog_publish_t *); + self = va_arg(*app, tsip_dialog_publish_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - return send_PUBLISH(self); + return send_PUBLISH(self); } /* Trying -> (1xx) -> Trying */ int tsip_dialog_publish_Trying_2_Trying_X_1xx(va_list *app) { - /*tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *);*/ - /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ + /*tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *);*/ + /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ - return 0; + return 0; } /* Trying -> (2xx) -> Terminated */ int tsip_dialog_publish_Trying_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Trying -> (2xx) -> Connected */ int tsip_dialog_publish_Trying_2_Connected_X_2xx(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - int ret; - - tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); - - /* RFC 3903 - 4.1. Identification of Published Event State - For each successful PUBLISH request, the ESC will generate and assign - an entity-tag and return it in the SIP-ETag header field of the 2xx - response. - */ - const tsip_header_SIP_ETag_t *SIP_ETag; - if((SIP_ETag = (const tsip_header_SIP_ETag_t*)tsip_message_get_header(response, tsip_htype_SIP_ETag))){ - tsk_strupdate(&self->etag, SIP_ETag->value); - } - - /* Alert the user (session)*/ - TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - /* Alert the user (dialog)*/ - if(first_time_to_connect){ /* PUBLISH not dialog oriented ...but */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - } - - /* Update the dialog state */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - return ret; - } - - /* Reset current action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - - /* Request timeout for dialog refresh (re-publish). */ - self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); - TSIP_DIALOG_PUBLISH_TIMER_SCHEDULE(refresh); - - return 0; + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + int ret; + + tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); + + /* RFC 3903 - 4.1. Identification of Published Event State + For each successful PUBLISH request, the ESC will generate and assign + an entity-tag and return it in the SIP-ETag header field of the 2xx + response. + */ + const tsip_header_SIP_ETag_t *SIP_ETag; + if((SIP_ETag = (const tsip_header_SIP_ETag_t*)tsip_message_get_header(response, tsip_htype_SIP_ETag))) { + tsk_strupdate(&self->etag, SIP_ETag->value); + } + + /* Alert the user (session)*/ + TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user (dialog)*/ + if(first_time_to_connect) { /* PUBLISH not dialog oriented ...but */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + } + + /* Update the dialog state */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + return ret; + } + + /* Reset current action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + + /* Request timeout for dialog refresh (re-publish). */ + self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); + TSIP_DIALOG_PUBLISH_TIMER_SCHEDULE(refresh); + + return 0; } /* Trying -> (401/407/421/494) -> Trying */ int tsip_dialog_publish_Trying_2_Trying_X_401_407_421_494(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_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_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - return send_PUBLISH(self); + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_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_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return ret; + } + + return send_PUBLISH(self); } /* Trying -> (423) -> Trying */ int tsip_dialog_publish_Trying_2_Trying_X_423(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - tsip_header_Min_Expires_t *hdr; - - /* - RFC 3261 - 10.2.8 Error Responses - - If a UA receives a 423 (Interval Too Brief) response, it MAY retry - the registration after making the expiration interval of all contact - addresses in the PUBLISH request equal to or greater than the - expiration interval within the Min-Expires header field of the 423 - (Interval Too Brief) response. - */ - hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(response, tsip_htype_Min_Expires); - if(hdr){ - TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); - send_PUBLISH(self); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_message_error, "Received invalid SIP response"); - - return -1; - } - - return 0; + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + tsip_header_Min_Expires_t *hdr; + + /* + RFC 3261 - 10.2.8 Error Responses + + If a UA receives a 423 (Interval Too Brief) response, it MAY retry + the registration after making the expiration interval of all contact + addresses in the PUBLISH request equal to or greater than the + expiration interval within the Min-Expires header field of the 423 + (Interval Too Brief) response. + */ + hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(response, tsip_htype_Min_Expires); + if(hdr) { + TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); + send_PUBLISH(self); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_message_error, "Received invalid SIP response"); + + return -1; + } + + return 0; } /* Trying -> (300 to 699) -> Terminated */ int tsip_dialog_publish_Trying_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_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_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Trying -> (cancel) -> Terminated */ int tsip_dialog_publish_Trying_2_Terminated_X_cancel(va_list *app) { - int ret; - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ + int ret; + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ - /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed (worth nothing)) */ - ret = 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)) */ + ret = tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - /* 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. + */ - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Subscription cancelled"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Subscription cancelled"); - return ret; + return ret; } /* Connected -> (PUBLISH) -> Trying */ int tsip_dialog_publish_Connected_2_Trying_X_publish(va_list *app) { - tsip_dialog_publish_t *self; + tsip_dialog_publish_t *self; - self = va_arg(*app, tsip_dialog_publish_t *); + self = va_arg(*app, tsip_dialog_publish_t *); - return send_PUBLISH(self); + return send_PUBLISH(self); } /* Connected -> (hangup) -> Trying */ int tsip_dialog_publish_Any_2_Trying_X_hangup(va_list *app) { - tsip_dialog_publish_t *self; + tsip_dialog_publish_t *self; + + self = va_arg(*app, tsip_dialog_publish_t *); - self = va_arg(*app, tsip_dialog_publish_t *); - - /* 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"); - self->unpublishing = tsk_true; - return send_PUBLISH(self); + self->unpublishing = tsk_true; + return send_PUBLISH(self); } /* Any -> (shutdown) -> Trying */ int tsip_dialog_publish_Any_2_Trying_X_shutdown(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - /* schedule shutdow timeout */ - TSIP_DIALOG_PUBLISH_TIMER_SCHEDULE(shutdown); + /* schedule shutdow timeout */ + TSIP_DIALOG_PUBLISH_TIMER_SCHEDULE(shutdown); - /* 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"); - self->unpublishing = tsk_true; - return send_PUBLISH(self); + self->unpublishing = tsk_true; + return send_PUBLISH(self); } /* Any -> (transport error) -> Terminated */ int tsip_dialog_publish_Any_2_Terminated_X_transportError(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - /* Alert the user. */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); + /* Alert the user. */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); - return 0; + return 0; } /* Any -> (Error) -> Terminated */ int tsip_dialog_publish_Any_2_Terminated_X_Error(va_list *app) { - tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - /* Alert the user. */ - if(response){ - TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); - } - - return 0; + tsip_dialog_publish_t *self = va_arg(*app, tsip_dialog_publish_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + /* Alert the user. */ + if(response) { + TSIP_DIALOG_PUBLISH_SIGNAL(self, self->unpublishing ? tsip_ao_unpublish : tsip_ao_publish, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); + } + + return 0; } @@ -561,59 +555,59 @@ int tsip_dialog_publish_Any_2_Terminated_X_Error(va_list *app) /** - * Sends a PUBLISH request. + * Sends a PUBLISH request. **/ int send_PUBLISH(tsip_dialog_publish_t *self) { - tsip_request_t *request = tsk_null; - int ret = -1; - const tsip_action_t* action; - - if(!self){ - return -1; - } - - // action - action = TSIP_DIALOG(self)->curr_action; - - if(self->unpublishing){ - TSIP_DIALOG(self)->expires = 0; - } - - /* RFC 3903 - 4.1. Identification of Published Event State - The presence of a body and the SIP-If-Match header field determine - the specific SSESSION that the request is performing, as described in Table 1. - +-----------+-------+---------------+---------------+ - | SSESSION | Body? | SIP-If-Match? | Expires Value | - +-----------+-------+---------------+---------------+ - | Initial | yes | no | > 0 | - | Refresh | no | yes | > 0 | - | Modify | yes | yes | > 0 | - | Remove | no | yes | 0 | - +-----------+-------+---------------+---------------+ - Table 1: Publication ssessions - */ - if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "PUBLISH"))){ - /*Etag. If initial then etag is null. */ - if(self->etag){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_SIP_IF_MATCH_VA_ARGS(self->etag)); - } - /*Body*/ - if(action && action->payload && !self->unpublishing){ - const tsk_list_item_t* item; - tsk_list_foreach(item, action->headers){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); - } - if(action->payload){ - tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload)); - } - } - - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - TSK_OBJECT_SAFE_FREE(request); - } - - return ret; + tsip_request_t *request = tsk_null; + int ret = -1; + const tsip_action_t* action; + + if(!self) { + return -1; + } + + // action + action = TSIP_DIALOG(self)->curr_action; + + if(self->unpublishing) { + TSIP_DIALOG(self)->expires = 0; + } + + /* RFC 3903 - 4.1. Identification of Published Event State + The presence of a body and the SIP-If-Match header field determine + the specific SSESSION that the request is performing, as described in Table 1. + +-----------+-------+---------------+---------------+ + | SSESSION | Body? | SIP-If-Match? | Expires Value | + +-----------+-------+---------------+---------------+ + | Initial | yes | no | > 0 | + | Refresh | no | yes | > 0 | + | Modify | yes | yes | > 0 | + | Remove | no | yes | 0 | + +-----------+-------+---------------+---------------+ + Table 1: Publication ssessions + */ + if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "PUBLISH"))) { + /*Etag. If initial then etag is null. */ + if(self->etag) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_SIP_IF_MATCH_VA_ARGS(self->etag)); + } + /*Body*/ + if(action && action->payload && !self->unpublishing) { + const tsk_list_item_t* item; + tsk_list_foreach(item, action->headers) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); + } + if(action->payload) { + tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload)); + } + } + + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + TSK_OBJECT_SAFE_FREE(request); + } + + return ret; } /** @@ -623,14 +617,14 @@ int send_PUBLISH(tsip_dialog_publish_t *self) **/ int tsip_dialog_publish_OnTerminated(tsip_dialog_publish_t *self) { - TSK_DEBUG_INFO("=== PUBLISH Dialog terminated ==="); + TSK_DEBUG_INFO("=== PUBLISH 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)); } @@ -650,52 +644,51 @@ int tsip_dialog_publish_OnTerminated(tsip_dialog_publish_t *self) // static tsk_object_t* tsip_dialog_publish_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_publish_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + tsip_dialog_publish_t *dialog = self; + if(dialog) { + tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); - /* init base class */ - tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_PUBLISH, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); + /* init base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_PUBLISH, 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_publish_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_publish_OnTerminated), (const void*)dialog); - /* init the class itself */ - tsip_dialog_publish_init(self); - } - return self; + /* init the class itself */ + tsip_dialog_publish_init(self); + } + return self; } static tsk_object_t* tsip_dialog_publish_dtor(tsk_object_t * _self) -{ - tsip_dialog_publish_t *self = _self; - if(self){ - TSK_DEBUG_INFO("*** PUBLISH Dialog destroyed ***"); - - /* Cancel all timers */ - TSIP_DIALOG_TIMER_CANCEL(refresh); - TSIP_DIALOG_TIMER_CANCEL(shutdown); - - /* deinit base class (will cancel all transactions) */ - tsip_dialog_deinit(TSIP_DIALOG(self)); - - /* deinit self*/ - TSK_FREE(self->etag); - } - return self; +{ + tsip_dialog_publish_t *self = _self; + if(self) { + TSK_DEBUG_INFO("*** PUBLISH Dialog destroyed ***"); + + /* Cancel all timers */ + TSIP_DIALOG_TIMER_CANCEL(refresh); + TSIP_DIALOG_TIMER_CANCEL(shutdown); + + /* deinit base class (will cancel all transactions) */ + tsip_dialog_deinit(TSIP_DIALOG(self)); + + /* deinit self*/ + TSK_FREE(self->etag); + } + return self; } static int tsip_dialog_publish_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_publish_def_s = -{ - sizeof(tsip_dialog_publish_t), - tsip_dialog_publish_ctor, - tsip_dialog_publish_dtor, - tsip_dialog_publish_cmp, +static const tsk_object_def_t tsip_dialog_publish_def_s = { + sizeof(tsip_dialog_publish_t), + tsip_dialog_publish_ctor, + tsip_dialog_publish_dtor, + tsip_dialog_publish_cmp, }; const tsk_object_def_t *tsip_dialog_publish_def_t = &tsip_dialog_publish_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_register.c b/tinySIP/src/dialogs/tsip_dialog_register.c index a1c1424..7a20cad 100755 --- a/tinySIP/src/dialogs/tsip_dialog_register.c +++ b/tinySIP/src/dialogs/tsip_dialog_register.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -52,11 +52,11 @@ static int tsip_dialog_register_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_silent_hangup(tsip_dialog_register_t* dialog, tsip_message_t* message) { - return TSIP_DIALOG(dialog)->ss->silent_hangup; + return TSIP_DIALOG(dialog)->ss->silent_hangup; } static tsk_bool_t _fsm_cond_not_silent_hangup(tsip_dialog_register_t* dialog, tsip_message_t* message) { - return !TSIP_DIALOG(dialog)->ss->silent_hangup; + return !TSIP_DIALOG(dialog)->ss->silent_hangup; } @@ -72,148 +72,146 @@ extern int tsip_dialog_register_server_init(tsip_dialog_register_t *self); * @brief Callback function called to alert the dialog for new events from the transaction/transport layers. * * @param [in,out] self A reference to the dialog. - * @param type The event type. - * @param [in,out] msg The incoming SIP/IMS message. + * @param type The event type. + * @param [in,out] msg The incoming SIP/IMS message. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_register_event_callback(const tsip_dialog_register_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)){ - 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); - } - else if(TSIP_RESPONSE_IS(msg,423)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); - } - else{ - // Alert User - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); - /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ - } - } - else{ - // - // REQUEST - // - if(TSIP_REQUEST_IS_REGISTER(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iREGISTER, 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)) { + // + // 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)) { + 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); + } + else if(TSIP_RESPONSE_IS(msg,423)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); + } + else { + // Alert User + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); + /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ + } + } + else { + // + // REQUEST + // + if(TSIP_REQUEST_IS_REGISTER(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_iREGISTER, 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; } /**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_register_timer_callback(const tsip_dialog_register_t* self, tsk_timer_id_t timer_id) { - int ret = -1; - - if(self){ - if(timer_id == self->timerrefresh.id){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oREGISTER, 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->timerrefresh.id) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_oREGISTER, 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; } /** Create SIP REGISTER dialog. */ tsip_dialog_register_t* tsip_dialog_register_create(const tsip_ssession_handle_t* ss, const char* call_id) { - return tsk_object_new(tsip_dialog_register_def_t, ss, call_id); + return tsk_object_new(tsip_dialog_register_def_t, ss, call_id); } /** Initializes the dialog. * - * @param [in,out] self The dialog to initialize. + * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_register_init(tsip_dialog_register_t *self) { - // Initialize client side - tsip_dialog_register_client_init(self); - // initialize server side - tsip_dialog_register_server_init(self); - - /* Initialize common side */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Any === - */ - // Any -> (hangup) -> InProgress - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_hangup, "tsip_dialog_register_Any_2_InProgress_X_hangup"), - // Any -> (silenthangup) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silenthangup"), - // Any -> (shutdown) -> InProgress - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_shutdown, "tsip_dialog_register_Any_2_InProgress_X_shutdown"), - // Any -> (silentshutdown) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silentshutdown"), - // Any -> (shutdown timedout) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_shutdown_timedout"), - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_transportError, "tsip_dialog_register_Any_2_Terminated_X_transportError"), - // Any -> (error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_Error, "tsip_dialog_register_Any_2_Terminated_X_Error"), - - TSK_FSM_ADD_NULL()); - - /* Sets callback function */ - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_register_event_callback); - - /* Timers */ - self->timerrefresh.id = TSK_INVALID_TIMER_ID; - self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; - self->timershutdown.id = TSK_INVALID_TIMER_ID; - self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; - - return 0; + // Initialize client side + tsip_dialog_register_client_init(self); + // initialize server side + tsip_dialog_register_server_init(self); + + /* Initialize common side */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Any === + */ + // Any -> (hangup) -> InProgress + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_hangup, "tsip_dialog_register_Any_2_InProgress_X_hangup"), + // Any -> (silenthangup) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silenthangup"), + // Any -> (shutdown) -> InProgress + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_InProgress, tsip_dialog_register_Any_2_InProgress_X_shutdown, "tsip_dialog_register_Any_2_InProgress_X_shutdown"), + // Any -> (silentshutdown) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_Any_2_InProgress_X_silentshutdown"), + // Any -> (shutdown timedout) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_shutdown_timedout"), + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_transportError, "tsip_dialog_register_Any_2_Terminated_X_transportError"), + // Any -> (error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_register_Any_2_Terminated_X_Error, "tsip_dialog_register_Any_2_Terminated_X_Error"), + + TSK_FSM_ADD_NULL()); + + /* Sets callback function */ + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_register_event_callback); + + /* Timers */ + self->timerrefresh.id = TSK_INVALID_TIMER_ID; + self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; + self->timershutdown.id = TSK_INVALID_TIMER_ID; + self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; + + return 0; } @@ -223,66 +221,66 @@ int tsip_dialog_register_init(tsip_dialog_register_t *self) */ int tsip_dialog_register_Any_2_InProgress_X_hangup(va_list *app) { - tsip_dialog_register_t *self; + tsip_dialog_register_t *self; - self = va_arg(*app, tsip_dialog_register_t *); + self = va_arg(*app, tsip_dialog_register_t *); - /* 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"); - self->unregistering = tsk_true; - return tsip_dialog_register_send_REGISTER(self, tsk_true); + self->unregistering = tsk_true; + return tsip_dialog_register_send_REGISTER(self, tsk_true); } /* Any -> (shutdown) -> InProgress */ int tsip_dialog_register_Any_2_InProgress_X_shutdown(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - - /* schedule shutdow timeout */ - TSIP_DIALOG_REGISTER_TIMER_SCHEDULE(shutdown); + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - /* alert user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + /* schedule shutdow timeout */ + TSIP_DIALOG_REGISTER_TIMER_SCHEDULE(shutdown); - self->unregistering = tsk_true; - return tsip_dialog_register_send_REGISTER(self, tsk_true); + /* alert user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + + self->unregistering = tsk_true; + return tsip_dialog_register_send_REGISTER(self, tsk_true); } /* Any -> (transport error) -> Terminated */ int tsip_dialog_register_Any_2_Terminated_X_transportError(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + /*const tsip_message_t *message = va_arg(*app, const tsip_message_t *);*/ - /* Alert the user. */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); + /* Alert the user. */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); - return 0; + return 0; } /* Any -> (error) -> Terminated */ int tsip_dialog_register_Any_2_Terminated_X_Error(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - /* save last error */ - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - - /* Alert the user. */ - if(response){ - TSIP_DIALOG_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); - } - - return 0; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + /* save last error */ + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + + /* Alert the user. */ + if(response) { + TSIP_DIALOG_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); + } + + return 0; } @@ -293,107 +291,107 @@ int tsip_dialog_register_Any_2_Terminated_X_Error(va_list *app) /** * - * Sends a REGISTER request. + * Sends a REGISTER request. * * @param [in,out] self The caller. * @param [in] initial Indicates whether it's an initial (new CSeq) REGISTER or not. * Initial REGISTER request will creates new IPSec temporary SAs. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_register_send_REGISTER(tsip_dialog_register_t *self, tsk_bool_t initial) { - tsip_request_t *request; - int ret = -1; - - /* whether we are unregistering */ - if(self->unregistering){ - TSIP_DIALOG(self)->expires = 0; - } - - /* creates REGISTER request */ - if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "REGISTER"))){ - /* == RCS phase 2 - */ - /*if(TSIP_DIALOG_GET_STACK(self)->enable_gsmarcs){ - TSIP_HEADER_ADD_PARAM(request->Contact, "+g.oma.sip-im.large-message", 0); - TSIP_HEADER_ADD_PARAM(request->Contact, "audio", 0); - TSIP_HEADER_ADD_PARAM(request->Contact, "video", 0); - TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.cs-voice", 0); - TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.icsi-ref", TSIP_ICSI_QUOTED_MMTEL_PSVOICE); - }*/ - - ///* mobility */ - //if(TSIP_DIALOG_GET_STACK(self)->mobility){ - // TSIP_HEADER_ADD_PARAM(request->Contact, "mobility", TSIP_DIALOG_GET_STACK(self)->mobility); - //} - - ///* deviceID - FIXME: find reference. */ - //if(TSIP_DIALOG_GET_STACK(self)->device_id){ - // TSIP_HEADER_ADD_PARAM(request->Contact, "+deviceID", TSIP_DIALOG_GET_STACK(self)->device_id); - //} - - ///* GSMA Image Sharing */ - //if(TSIP_DIALOG_GET_STACK(self)->enable_gsmais){ - // TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.app_ref", TSIP_IARI_QUOTED_GSMAIS); - //} - - ///* 3GPP TS 24.341 subclause 5.3.2.2 */ - //if(TSIP_DIALOG_GET_STACK(self)->enable_3gppsms){ - // TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.smsip", 0); - //} - - /* 3GPP TS 24.229 - 5.1.1.2 Initial registration */ - if(TSIP_DIALOG(self)->state ==tsip_initial){ - /* - g) the Supported header field containing the option-tag "path", and - 1) if GRUU is supported, the option-tag "gruu"; and - 2) if multiple registrations is supported, the option-tag "outbound". - */ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_SUPPORTED_VA_ARGS("path")); - //if(1==2/* gruu*/){ - //} - //else if(2 == 3 /* multiple registrations */){ - //} - } - - /* action parameters and payload */ - if(TSIP_DIALOG(self)->curr_action){ - const tsk_list_item_t* item; - tsk_list_foreach(item, TSIP_DIALOG(self)->curr_action->headers){ - TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); - } - if(TSIP_DIALOG(self)->curr_action->payload){ - tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(TSIP_DIALOG(self)->curr_action->payload), TSK_BUFFER_SIZE(TSIP_DIALOG(self)->curr_action->payload)); - } - } - - /* Create temorary SAs if initial register. */ - if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech){ - if(tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")){ - if(initial){ - tsip_transport_createTempSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); - } - else{ - AKA_CK_T ck; - AKA_IK_T ik; - tsip_dialog_getCKIK(TSIP_DIALOG(self), &ck, &ik); - tsip_transport_startSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport, (const tipsec_key_t*)ik, (const tipsec_key_t*)ck); - } - } - } - - if(!(ret = tsip_dialog_request_send(TSIP_DIALOG(self), request))){ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_sent, "(un)REGISTER request successfully sent."); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); - } - - TSK_OBJECT_SAFE_FREE(request); - } - - return ret; + tsip_request_t *request; + int ret = -1; + + /* whether we are unregistering */ + if(self->unregistering) { + TSIP_DIALOG(self)->expires = 0; + } + + /* creates REGISTER request */ + if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "REGISTER"))) { + /* == RCS phase 2 + */ + /*if(TSIP_DIALOG_GET_STACK(self)->enable_gsmarcs){ + TSIP_HEADER_ADD_PARAM(request->Contact, "+g.oma.sip-im.large-message", 0); + TSIP_HEADER_ADD_PARAM(request->Contact, "audio", 0); + TSIP_HEADER_ADD_PARAM(request->Contact, "video", 0); + TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.cs-voice", 0); + TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.icsi-ref", TSIP_ICSI_QUOTED_MMTEL_PSVOICE); + }*/ + + ///* mobility */ + //if(TSIP_DIALOG_GET_STACK(self)->mobility){ + // TSIP_HEADER_ADD_PARAM(request->Contact, "mobility", TSIP_DIALOG_GET_STACK(self)->mobility); + //} + + ///* deviceID - FIXME: find reference. */ + //if(TSIP_DIALOG_GET_STACK(self)->device_id){ + // TSIP_HEADER_ADD_PARAM(request->Contact, "+deviceID", TSIP_DIALOG_GET_STACK(self)->device_id); + //} + + ///* GSMA Image Sharing */ + //if(TSIP_DIALOG_GET_STACK(self)->enable_gsmais){ + // TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.app_ref", TSIP_IARI_QUOTED_GSMAIS); + //} + + ///* 3GPP TS 24.341 subclause 5.3.2.2 */ + //if(TSIP_DIALOG_GET_STACK(self)->enable_3gppsms){ + // TSIP_HEADER_ADD_PARAM(request->Contact, "+g.3gpp.smsip", 0); + //} + + /* 3GPP TS 24.229 - 5.1.1.2 Initial registration */ + if(TSIP_DIALOG(self)->state ==tsip_initial) { + /* + g) the Supported header field containing the option-tag "path", and + 1) if GRUU is supported, the option-tag "gruu"; and + 2) if multiple registrations is supported, the option-tag "outbound". + */ + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_SUPPORTED_VA_ARGS("path")); + //if(1==2/* gruu*/){ + //} + //else if(2 == 3 /* multiple registrations */){ + //} + } + + /* action parameters and payload */ + if(TSIP_DIALOG(self)->curr_action) { + const tsk_list_item_t* item; + tsk_list_foreach(item, TSIP_DIALOG(self)->curr_action->headers) { + TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value)); + } + if(TSIP_DIALOG(self)->curr_action->payload) { + tsip_message_add_content(request, tsk_null, TSK_BUFFER_DATA(TSIP_DIALOG(self)->curr_action->payload), TSK_BUFFER_SIZE(TSIP_DIALOG(self)->curr_action->payload)); + } + } + + /* Create temorary SAs if initial register. */ + if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech) { + if(tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")) { + if(initial) { + tsip_transport_createTempSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); + } + else { + AKA_CK_T ck; + AKA_IK_T ik; + tsip_dialog_getCKIK(TSIP_DIALOG(self), &ck, &ik); + tsip_transport_startSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport, (const tipsec_key_t*)ik, (const tipsec_key_t*)ck); + } + } + } + + if(!(ret = tsip_dialog_request_send(TSIP_DIALOG(self), request))) { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_sent, "(un)REGISTER request successfully sent."); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); + } + + TSK_OBJECT_SAFE_FREE(request); + } + + return ret; } @@ -401,19 +399,19 @@ int tsip_dialog_register_send_REGISTER(tsip_dialog_register_t *self, tsk_bool_t // Send any response int tsip_dialog_register_send_RESPONSE(tsip_dialog_register_t *self, const tsip_request_t* request, short code, const char* phrase) { - tsip_response_t *response; - int ret = -1; - - if(!self || !request){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 1; - } - - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))){ - ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - return ret; + tsip_response_t *response; + int ret = -1; + + if(!self || !request) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 1; + } + + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), code, phrase, request))) { + ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + return ret; } @@ -427,23 +425,23 @@ int tsip_dialog_register_send_RESPONSE(tsip_dialog_register_t *self, const tsip_ **/ int tsip_dialog_register_OnTerminated(tsip_dialog_register_t *self) { - TSK_DEBUG_INFO("=== REGISTER Dialog terminated ==="); - - /* Cleanup IPSec SAs */ - if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech && tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")){ - tsip_transport_cleanupSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); - } - /* Reset values to avoid issues when the session is reused */ - self->unregistering = tsk_false; - TSK_OBJECT_SAFE_FREE(self->last_iRegister); - - /* 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 : "Dialog terminated", - TSIP_DIALOG(self)->last_error.message); - - /* Remove from the dialog layer. */ - return tsip_dialog_remove(TSIP_DIALOG(self)); + TSK_DEBUG_INFO("=== REGISTER Dialog terminated ==="); + + /* Cleanup IPSec SAs */ + if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech && tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")) { + tsip_transport_cleanupSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); + } + /* Reset values to avoid issues when the session is reused */ + self->unregistering = tsk_false; + TSK_OBJECT_SAFE_FREE(self->last_iRegister); + + /* 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 : "Dialog terminated", + TSIP_DIALOG(self)->last_error.message); + + /* Remove from the dialog layer. */ + return tsip_dialog_remove(TSIP_DIALOG(self)); } @@ -454,54 +452,53 @@ int tsip_dialog_register_OnTerminated(tsip_dialog_register_t *self) // static tsk_object_t* tsip_dialog_register_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_register_t *dialog = self; - if(dialog){ - tsip_ssession_t *ss = va_arg(*app, tsip_ssession_t *); - const char* call_id = va_arg(*app, const char *); - - /* Initialize base class */ - tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_REGISTER, call_id, ss, _fsm_state_Started, _fsm_state_Terminated); - - /* create 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_register_OnTerminated), (const void*)dialog); - - /* Initialize the class itself */ - tsip_dialog_register_init(self); - } - return self; + tsip_dialog_register_t *dialog = self; + if(dialog) { + tsip_ssession_t *ss = va_arg(*app, tsip_ssession_t *); + const char* call_id = va_arg(*app, const char *); + + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_REGISTER, call_id, ss, _fsm_state_Started, _fsm_state_Terminated); + + /* create 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_register_OnTerminated), (const void*)dialog); + + /* Initialize the class itself */ + tsip_dialog_register_init(self); + } + return self; } static tsk_object_t* tsip_dialog_register_dtor(tsk_object_t * _self) -{ - tsip_dialog_register_t *self = _self; - if(self){ +{ + tsip_dialog_register_t *self = _self; + if(self) { - /* Cancel all timers */ - TSIP_DIALOG_TIMER_CANCEL(refresh); - TSIP_DIALOG_TIMER_CANCEL(shutdown); + /* Cancel all timers */ + TSIP_DIALOG_TIMER_CANCEL(refresh); + TSIP_DIALOG_TIMER_CANCEL(shutdown); - /* DeInitialize base class (will cancel all transactions) */ - tsip_dialog_deinit(TSIP_DIALOG(self)); + /* DeInitialize base class (will cancel all transactions) */ + tsip_dialog_deinit(TSIP_DIALOG(self)); - // Delete resources - TSK_OBJECT_SAFE_FREE(self->last_iRegister); + // Delete resources + TSK_OBJECT_SAFE_FREE(self->last_iRegister); - TSK_DEBUG_INFO("*** REGISTER Dialog destroyed ***"); - } - return self; + TSK_DEBUG_INFO("*** REGISTER Dialog destroyed ***"); + } + return self; } static int tsip_dialog_register_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_register_def_s = -{ - sizeof(tsip_dialog_register_t), - tsip_dialog_register_ctor, - tsip_dialog_register_dtor, - tsip_dialog_register_cmp, +static const tsk_object_def_t tsip_dialog_register_def_s = { + sizeof(tsip_dialog_register_t), + tsip_dialog_register_ctor, + tsip_dialog_register_dtor, + tsip_dialog_register_cmp, }; const tsk_object_def_t *tsip_dialog_register_def_t = &tsip_dialog_register_def_s; diff --git a/tinySIP/src/dialogs/tsip_dialog_register.client.c b/tinySIP/src/dialogs/tsip_dialog_register.client.c index fa5e99b..17fe334 100755 --- a/tinySIP/src/dialogs/tsip_dialog_register.client.c +++ b/tinySIP/src/dialogs/tsip_dialog_register.client.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -59,67 +59,67 @@ static int tsip_dialog_register_Connected_2_InProgress_X_oRegister(va_list *app) /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_client_unregistering(tsip_dialog_register_t* dialog, tsip_message_t* message) { - return !dialog->is_server && dialog->unregistering; + return !dialog->is_server && dialog->unregistering; } static tsk_bool_t _fsm_cond_client_registering(tsip_dialog_register_t* dialog, tsip_message_t* message) { - return !_fsm_cond_client_unregistering(dialog, message); + return !_fsm_cond_client_unregistering(dialog, message); } /** Initializes the dialog. * - * @param [in,out] self The dialog to initialize. + * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_register_client_init(tsip_dialog_register_t *self) { - /* Initialize the state machine. */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (REGISTER) -> InProgress - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_oREGISTER, _fsm_state_InProgress, tsip_dialog_register_Started_2_InProgress_X_oRegister, "tsip_dialog_register_Started_2_InProgress_X_oRegister"), - // Started -> (Any) -> Started - //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_register_Started_2_Started_X_any"), - - - /*======================= - * === InProgress === - */ - // InProgress -> (1xx) -> InProgress - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_1xx, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_1xx, "tsip_dialog_register_InProgress_2_InProgress_X_1xx"), - // InProgress -> (2xx) -> Terminated - TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_2xx, _fsm_cond_client_unregistering, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_2xx, "tsip_dialog_register_InProgress_2_Terminated_X_2xx"), - // InProgress -> (2xx) -> Connected - TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_2xx, _fsm_cond_client_registering, _fsm_state_Connected, tsip_dialog_register_InProgress_2_Connected_X_2xx, "tsip_dialog_register_InProgress_2_Connected_X_2xx"), - // InProgress -> (401/407/421/494) -> InProgress - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_401_407_421_494, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_401_407_421_494, "tsip_dialog_register_InProgress_2_InProgress_X_401_407_421_494"), - // InProgress -> (423) -> InProgress - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_423, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_423, "tsip_dialog_register_InProgress_2_InProgress_X_423"), - // InProgress -> (300_to_699) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_300_to_699, "tsip_dialog_register_InProgress_2_Terminated_X_300_to_699"), - // InProgress -> (cancel) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_cancel, "tsip_dialog_register_InProgress_2_Terminated_X_cancel"), - // InProgress -> (hangup) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_InProgress_2_Terminated_X_hangup"), - // InProgress -> (shutdown) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_InProgress_2_Terminated_X_shutdown"), - // InProgress -> (Any) -> InProgress - //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_InProgress, "tsip_dialog_register_InProgress_2_InProgress_X_any"), - - - /*======================= - * === Connected === - */ - // Connected -> (register) -> InProgress [refresh case] - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oREGISTER, _fsm_state_InProgress, tsip_dialog_register_Connected_2_InProgress_X_oRegister, "tsip_dialog_register_Connected_2_InProgress_X_oRegister"), - - - TSK_FSM_ADD_NULL()); - - return 0; + /* Initialize the state machine. */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (REGISTER) -> InProgress + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_oREGISTER, _fsm_state_InProgress, tsip_dialog_register_Started_2_InProgress_X_oRegister, "tsip_dialog_register_Started_2_InProgress_X_oRegister"), + // Started -> (Any) -> Started + //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_register_Started_2_Started_X_any"), + + + /*======================= + * === InProgress === + */ + // InProgress -> (1xx) -> InProgress + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_1xx, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_1xx, "tsip_dialog_register_InProgress_2_InProgress_X_1xx"), + // InProgress -> (2xx) -> Terminated + TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_2xx, _fsm_cond_client_unregistering, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_2xx, "tsip_dialog_register_InProgress_2_Terminated_X_2xx"), + // InProgress -> (2xx) -> Connected + TSK_FSM_ADD(_fsm_state_InProgress, _fsm_action_2xx, _fsm_cond_client_registering, _fsm_state_Connected, tsip_dialog_register_InProgress_2_Connected_X_2xx, "tsip_dialog_register_InProgress_2_Connected_X_2xx"), + // InProgress -> (401/407/421/494) -> InProgress + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_401_407_421_494, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_401_407_421_494, "tsip_dialog_register_InProgress_2_InProgress_X_401_407_421_494"), + // InProgress -> (423) -> InProgress + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_423, _fsm_state_InProgress, tsip_dialog_register_InProgress_2_InProgress_X_423, "tsip_dialog_register_InProgress_2_InProgress_X_423"), + // InProgress -> (300_to_699) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_300_to_699, "tsip_dialog_register_InProgress_2_Terminated_X_300_to_699"), + // InProgress -> (cancel) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_register_InProgress_2_Terminated_X_cancel, "tsip_dialog_register_InProgress_2_Terminated_X_cancel"), + // InProgress -> (hangup) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_InProgress_2_Terminated_X_hangup"), + // InProgress -> (shutdown) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_InProgress, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_register_InProgress_2_Terminated_X_shutdown"), + // InProgress -> (Any) -> InProgress + //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_InProgress, "tsip_dialog_register_InProgress_2_InProgress_X_any"), + + + /*======================= + * === Connected === + */ + // Connected -> (register) -> InProgress [refresh case] + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_oREGISTER, _fsm_state_InProgress, tsip_dialog_register_Connected_2_InProgress_X_oRegister, "tsip_dialog_register_Connected_2_InProgress_X_oRegister"), + + + TSK_FSM_ADD_NULL()); + + return 0; } //-------------------------------------------------------- @@ -130,30 +130,30 @@ int tsip_dialog_register_client_init(tsip_dialog_register_t *self) */ int tsip_dialog_register_Started_2_InProgress_X_oRegister(va_list *app) { - tsip_dialog_register_t *self; + tsip_dialog_register_t *self; - self = va_arg(*app, tsip_dialog_register_t *); + self = va_arg(*app, tsip_dialog_register_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - return tsip_dialog_register_send_REGISTER(self, tsk_true); + return tsip_dialog_register_send_REGISTER(self, tsk_true); } /* InProgress -> (1xx) -> InProgress */ int tsip_dialog_register_InProgress_2_InProgress_X_1xx(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user (session) */ - TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_register, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user (session) */ + TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_register, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return tsip_dialog_update(TSIP_DIALOG(self), response); + return tsip_dialog_update(TSIP_DIALOG(self), response); } /* InProgress -> (2xx) -> Connected @@ -161,248 +161,248 @@ int tsip_dialog_register_InProgress_2_InProgress_X_1xx(va_list *app) //#include "tsk_thread.h" int tsip_dialog_register_InProgress_2_Connected_X_2xx(va_list *app) { - int ret; - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); - - /* - Set P-associated-uriS - * - Update service-routes - * - Update Pats - */ - { - tsk_size_t index; - const tsip_header_Path_t *hdr_Path; - const tsip_header_Service_Route_t *hdr_Service_Route; - const tsip_header_P_Associated_URI_t *hdr_P_Associated_URI_t; - tsip_uri_t *uri; - - /* To avoid memory leaks ==> delete all concerned objects (it worth nothing) */ - TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->associated_uris); - TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->service_routes); - TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->paths); - - /* Associated URIs */ - for(index = 0; (hdr_P_Associated_URI_t = (const tsip_header_P_Associated_URI_t*)tsip_message_get_headerAt(response, tsip_htype_P_Associated_URI, index)); index++){ - if(!TSIP_DIALOG_GET_STACK(self)->associated_uris){ - TSIP_DIALOG_GET_STACK(self)->associated_uris = tsk_list_create(); - } - uri = tsk_object_ref(hdr_P_Associated_URI_t->uri); - tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->associated_uris, (void**)&uri); - } - - /* Service-Route (3GPP TS 24.229) - store the list of service route values contained in the Service-Route header field and bind the list to the contact - address used in registration, in order to build a proper preloaded Route header field value for new dialogs and - standalone transactions when using the respective contact address. - */ - for(index = 0; (hdr_Service_Route = (const tsip_header_Service_Route_t*)tsip_message_get_headerAt(response, tsip_htype_Service_Route, index)); index++){ - if(!TSIP_DIALOG_GET_STACK(self)->service_routes){ - TSIP_DIALOG_GET_STACK(self)->service_routes = tsk_list_create(); - } - uri = tsk_object_ref(hdr_Service_Route->uri); - tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->service_routes, (void**)&uri); - } - - /* Paths */ - for(index = 0; (hdr_Path = (const tsip_header_Path_t*)tsip_message_get_headerAt(response, tsip_htype_Path, index)); index++){ - if(TSIP_DIALOG_GET_STACK(self)->paths == 0){ - TSIP_DIALOG_GET_STACK(self)->paths = tsk_list_create(); - } - uri = tsk_object_ref(hdr_Path->uri); - tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->paths, (void**)&uri); - } - } - - /* 3GPP TS 24.229 - 5.1.1.2 Initial registration */ - if(first_time_to_connect){ - tsk_bool_t barred = tsk_true; - const tsk_list_item_t *item; - const tsip_uri_t *uri; - const tsip_uri_t *uri_first = 0; - - /* - b) store as the default public user identity the first URI on the list of URIs present in the P-Associated-URI header - field and bind it to the respective contact address of the UE and the associated set of security associations or TLS - session; - NOTE 4: When using the respective contact address and associated set of security associations or TLS session, the - UE can utilize additional URIs contained in the P-Associated-URI header field and bound it to the - respective contact address of the UE and the associated set of security associations or TLS session, e.g. for - application purposes. - c) treat the identity under registration as a barred public user identity, if it is not included in the P-Associated-URI - header field; - */ - tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->associated_uris){ - uri = item->data; - if(item == TSIP_DIALOG_GET_STACK(self)->associated_uris->head){ - uri_first = item->data; - } - if(!tsk_object_cmp(TSIP_DIALOG_GET_STACK(self)->identity.preferred, uri)){ - barred = 0; - break; - } - } - - if(barred && uri_first){ - TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->identity.preferred); - TSIP_DIALOG_GET_STACK(self)->identity.preferred = tsk_object_ref((void*)uri_first); - } - } - - /* Update the dialog state */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - return ret; - } - - /* Reset current action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - - /* Request timeout for dialog refresh (re-registration). */ - self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); - TSIP_DIALOG_REGISTER_TIMER_SCHEDULE(refresh); - - /* Alert the user (session) */ - TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_register, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - /* Alert the user (dialog) */ - if(first_time_to_connect){ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - } - - return ret; + int ret; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); + + /* - Set P-associated-uriS + * - Update service-routes + * - Update Pats + */ + { + tsk_size_t index; + const tsip_header_Path_t *hdr_Path; + const tsip_header_Service_Route_t *hdr_Service_Route; + const tsip_header_P_Associated_URI_t *hdr_P_Associated_URI_t; + tsip_uri_t *uri; + + /* To avoid memory leaks ==> delete all concerned objects (it worth nothing) */ + TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->associated_uris); + TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->service_routes); + TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->paths); + + /* Associated URIs */ + for(index = 0; (hdr_P_Associated_URI_t = (const tsip_header_P_Associated_URI_t*)tsip_message_get_headerAt(response, tsip_htype_P_Associated_URI, index)); index++) { + if(!TSIP_DIALOG_GET_STACK(self)->associated_uris) { + TSIP_DIALOG_GET_STACK(self)->associated_uris = tsk_list_create(); + } + uri = tsk_object_ref(hdr_P_Associated_URI_t->uri); + tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->associated_uris, (void**)&uri); + } + + /* Service-Route (3GPP TS 24.229) + store the list of service route values contained in the Service-Route header field and bind the list to the contact + address used in registration, in order to build a proper preloaded Route header field value for new dialogs and + standalone transactions when using the respective contact address. + */ + for(index = 0; (hdr_Service_Route = (const tsip_header_Service_Route_t*)tsip_message_get_headerAt(response, tsip_htype_Service_Route, index)); index++) { + if(!TSIP_DIALOG_GET_STACK(self)->service_routes) { + TSIP_DIALOG_GET_STACK(self)->service_routes = tsk_list_create(); + } + uri = tsk_object_ref(hdr_Service_Route->uri); + tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->service_routes, (void**)&uri); + } + + /* Paths */ + for(index = 0; (hdr_Path = (const tsip_header_Path_t*)tsip_message_get_headerAt(response, tsip_htype_Path, index)); index++) { + if(TSIP_DIALOG_GET_STACK(self)->paths == 0) { + TSIP_DIALOG_GET_STACK(self)->paths = tsk_list_create(); + } + uri = tsk_object_ref(hdr_Path->uri); + tsk_list_push_back_data(TSIP_DIALOG_GET_STACK(self)->paths, (void**)&uri); + } + } + + /* 3GPP TS 24.229 - 5.1.1.2 Initial registration */ + if(first_time_to_connect) { + tsk_bool_t barred = tsk_true; + const tsk_list_item_t *item; + const tsip_uri_t *uri; + const tsip_uri_t *uri_first = 0; + + /* + b) store as the default public user identity the first URI on the list of URIs present in the P-Associated-URI header + field and bind it to the respective contact address of the UE and the associated set of security associations or TLS + session; + NOTE 4: When using the respective contact address and associated set of security associations or TLS session, the + UE can utilize additional URIs contained in the P-Associated-URI header field and bound it to the + respective contact address of the UE and the associated set of security associations or TLS session, e.g. for + application purposes. + c) treat the identity under registration as a barred public user identity, if it is not included in the P-Associated-URI + header field; + */ + tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->associated_uris) { + uri = item->data; + if(item == TSIP_DIALOG_GET_STACK(self)->associated_uris->head) { + uri_first = item->data; + } + if(!tsk_object_cmp(TSIP_DIALOG_GET_STACK(self)->identity.preferred, uri)) { + barred = 0; + break; + } + } + + if(barred && uri_first) { + TSK_OBJECT_SAFE_FREE(TSIP_DIALOG_GET_STACK(self)->identity.preferred); + TSIP_DIALOG_GET_STACK(self)->identity.preferred = tsk_object_ref((void*)uri_first); + } + } + + /* Update the dialog state */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + return ret; + } + + /* Reset current action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + + /* Request timeout for dialog refresh (re-registration). */ + self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); + TSIP_DIALOG_REGISTER_TIMER_SCHEDULE(refresh); + + /* Alert the user (session) */ + TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_register, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user (dialog) */ + if(first_time_to_connect) { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + } + + return ret; } /* InProgress -> (2xx) -> Terminated */ int tsip_dialog_register_InProgress_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* save last error */ - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + /* save last error */ + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - /* Alert the user */ - TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_unregister, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user */ + TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_ao_unregister, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* InProgress --> (401/407/421/494) --> InProgress */ int tsip_dialog_register_InProgress_2_InProgress_X_401_407_421_494(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_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_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - /* set last error (or info) */ - tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Authentication failed", TSIP_RESPONSE_CODE(response)); - - return ret; - } - - /* Ensure IPSec SAs */ - if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech && tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")){ - tsip_transport_ensureTempSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport, response, TSIP_DIALOG(self)->expires); - } - - return tsip_dialog_register_send_REGISTER(self, tsk_false); + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_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_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + /* set last error (or info) */ + tsip_dialog_set_lasterror(TSIP_DIALOG(self), "Authentication failed", TSIP_RESPONSE_CODE(response)); + + return ret; + } + + /* Ensure IPSec SAs */ + if(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech && tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")) { + tsip_transport_ensureTempSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport, response, TSIP_DIALOG(self)->expires); + } + + return tsip_dialog_register_send_REGISTER(self, tsk_false); } /* InProgress -> (423) -> InProgress */ int tsip_dialog_register_InProgress_2_InProgress_X_423(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_message_t *message = va_arg(*app, const tsip_message_t *); - - tsip_header_Min_Expires_t *hdr; - int ret = 0; - - /* - RFC 3261 - 10.2.8 Error Responses - - If a UA receives a 423 (Interval Too Brief) response, it MAY retry - the registration after making the expiration interval of all contact - addresses in the REGISTER request equal to or greater than the - expiration interval within the Min-Expires header field of the 423 - (Interval Too Brief) response. - */ - hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(message, tsip_htype_Min_Expires); - if(hdr){ - TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); - - if(tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")){ - tsip_transport_cleanupSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); - ret = tsip_dialog_register_send_REGISTER(self, tsk_true); - } - else{ - ret = tsip_dialog_register_send_REGISTER(self, tsk_false); - } - } - else{ - TSK_DEBUG_ERROR("Missing header: Min_Expires"); - ret = -1; - } - - return ret; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_message_t *message = va_arg(*app, const tsip_message_t *); + + tsip_header_Min_Expires_t *hdr; + int ret = 0; + + /* + RFC 3261 - 10.2.8 Error Responses + + If a UA receives a 423 (Interval Too Brief) response, it MAY retry + the registration after making the expiration interval of all contact + addresses in the REGISTER request equal to or greater than the + expiration interval within the Min-Expires header field of the 423 + (Interval Too Brief) response. + */ + hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(message, tsip_htype_Min_Expires); + if(hdr) { + TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); + + if(tsk_striequals(TSIP_DIALOG_GET_STACK(self)->security.secagree_mech, "ipsec-3gpp")) { + tsip_transport_cleanupSAs(TSIP_DIALOG_GET_STACK(self)->layer_transport); + ret = tsip_dialog_register_send_REGISTER(self, tsk_true); + } + else { + ret = tsip_dialog_register_send_REGISTER(self, tsk_false); + } + } + else { + TSK_DEBUG_ERROR("Missing header: Min_Expires"); + ret = -1; + } + + return ret; } /* InProgress -> (300-699) -> Terminated */ int tsip_dialog_register_InProgress_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - - /* save last error */ - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - - /* Alert the user. */ - TSIP_DIALOG_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return 0; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + /* save last error */ + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + + /* Alert the user. */ + TSIP_DIALOG_REGISTER_SIGNAL(self, self->unregistering ? tsip_ao_unregister : tsip_ao_register, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + + return 0; } /* InProgress -> (cancel) -> Terminated */ int tsip_dialog_register_InProgress_2_Terminated_X_cancel(va_list *app) { - int ret; - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ + int ret; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + /* const tsip_message_t *message = va_arg(*app, const tsip_message_t *); */ - /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed (worth nothing)) */ - ret = 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)) */ + ret = tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - /* 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. + */ - /* Alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Registration cancelled"); + /* Alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Registration cancelled"); - return ret; + return ret; } /* Connected -> (REGISTER) -> InProgress */ int tsip_dialog_register_Connected_2_InProgress_X_oRegister(va_list *app) { - tsip_dialog_register_t *self; + tsip_dialog_register_t *self; - self = va_arg(*app, tsip_dialog_register_t *); + self = va_arg(*app, tsip_dialog_register_t *); - return tsip_dialog_register_send_REGISTER(self, tsk_true); + return tsip_dialog_register_send_REGISTER(self, tsk_true); } diff --git a/tinySIP/src/dialogs/tsip_dialog_register.server.c b/tinySIP/src/dialogs/tsip_dialog_register.server.c index de912ff..3317bce 100755 --- a/tinySIP/src/dialogs/tsip_dialog_register.server.c +++ b/tinySIP/src/dialogs/tsip_dialog_register.server.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -39,68 +39,68 @@ static int s0000_Connected_2_Terminated_X_iREGISTER(va_list *app); static tsk_bool_t _fsm_cond_not_served_here(tsip_dialog_register_t* dialog, tsip_message_t* message) { #if 0 // FIXME: Have to disabled only when in proxy mode - if(message && TSIP_REQUEST_IS_REGISTER(message)){ - if(tsk_object_cmp(TSIP_DIALOG_GET_STACK(dialog)->network.realm, message->line.request.uri) != 0){ - tsip_dialog_register_send_RESPONSE(dialog, TSIP_MESSAGE_AS_REQUEST(message), 404, "Domain not served here"); - return tsk_true; - } - } + if(message && TSIP_REQUEST_IS_REGISTER(message)) { + if(tsk_object_cmp(TSIP_DIALOG_GET_STACK(dialog)->network.realm, message->line.request.uri) != 0) { + tsip_dialog_register_send_RESPONSE(dialog, TSIP_MESSAGE_AS_REQUEST(message), 404, "Domain not served here"); + return tsk_true; + } + } #endif - return tsk_false; + return tsk_false; } static tsk_bool_t _fsm_cond_server_unregistering(tsip_dialog_register_t* dialog, tsip_message_t* message) { - if(message && dialog->is_server){ - int64_t expires = tsip_message_getExpires(message); - dialog->unregistering = (expires == 0); - return dialog->unregistering; - } - return tsk_false; + if(message && dialog->is_server) { + int64_t expires = tsip_message_getExpires(message); + dialog->unregistering = (expires == 0); + return dialog->unregistering; + } + return tsk_false; } static tsk_bool_t _fsm_cond_server_registering(tsip_dialog_register_t* dialog, tsip_message_t* message) { - return !_fsm_cond_server_unregistering(dialog, message); + return !_fsm_cond_server_unregistering(dialog, message); } int tsip_dialog_register_server_init(tsip_dialog_register_t *self) { - return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (Domain Not Served here) -> Terminated - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iREGISTER, _fsm_cond_not_served_here, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iREGISTER, "s0000_Started_2_Terminated_X_iREGISTER"), - // Started -> (All is OK and we are not unRegistering) -> Trying - TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Incoming, s0000_Started_2_Incoming_X_iREGISTER, "s0000_Started_2_Incoming_X_iREGISTER"), - - /*======================= - * === Incoming === - */ - // Incoming -> (Accept) -> Connected - TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_accept, _fsm_state_Connected, s0000_Incoming_2_Connected_X_Accept, "s0000_Incoming_2_Connected_X_Accept"), - // Incoming -> (iRegister) -> Incoming - TSK_FSM_ADD(_fsm_state_Incoming, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Incoming, tsk_null, "s0000_Incoming_2_Incoming_X_iREGISTER"), - // Incoming -> (iRegister, expires=0) -> Terminated - TSK_FSM_ADD(_fsm_state_Incoming, _fsm_action_iREGISTER, _fsm_cond_server_unregistering, _fsm_state_Terminated, tsk_null, "s0000_Incoming_2_Terminated_X_iREGISTER"), - // Incoming -> (Reject) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_reject, _fsm_state_Terminated, s0000_Incoming_2_Terminated_X_Terminates, "s0000_Incoming_2_Terminated_X_Terminates"), - // Incoming -> (Hangup) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_hangup, _fsm_state_Terminated, s0000_Incoming_2_Terminated_X_Terminates, "s0000_Incoming_2_Terminated_X_Terminates"), - - /*======================= - * === Connected === - */ - // Connected -> (Register) -> Connected - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Connected, s0000_Connected_2_Connected_X_iREGISTER, "s0000_Connected_2_Connected_X_iREGISTER"), - // Connected -> (UnRegister) -> Terminated - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREGISTER, _fsm_cond_server_unregistering, _fsm_state_Terminated, s0000_Connected_2_Terminated_X_iREGISTER, "s0000_Connected_2_Terminated_X_iREGISTER"), - // Connected -> (TimedOut) -> Terminated - // Connected -> (Refresh OK) -> Connected - // Connected -> (Refresh NOK) -> Terminated - - TSK_FSM_ADD_NULL()); + return tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (Domain Not Served here) -> Terminated + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iREGISTER, _fsm_cond_not_served_here, _fsm_state_Terminated, s0000_Started_2_Terminated_X_iREGISTER, "s0000_Started_2_Terminated_X_iREGISTER"), + // Started -> (All is OK and we are not unRegistering) -> Trying + TSK_FSM_ADD(_fsm_state_Started, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Incoming, s0000_Started_2_Incoming_X_iREGISTER, "s0000_Started_2_Incoming_X_iREGISTER"), + + /*======================= + * === Incoming === + */ + // Incoming -> (Accept) -> Connected + TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_accept, _fsm_state_Connected, s0000_Incoming_2_Connected_X_Accept, "s0000_Incoming_2_Connected_X_Accept"), + // Incoming -> (iRegister) -> Incoming + TSK_FSM_ADD(_fsm_state_Incoming, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Incoming, tsk_null, "s0000_Incoming_2_Incoming_X_iREGISTER"), + // Incoming -> (iRegister, expires=0) -> Terminated + TSK_FSM_ADD(_fsm_state_Incoming, _fsm_action_iREGISTER, _fsm_cond_server_unregistering, _fsm_state_Terminated, tsk_null, "s0000_Incoming_2_Terminated_X_iREGISTER"), + // Incoming -> (Reject) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_reject, _fsm_state_Terminated, s0000_Incoming_2_Terminated_X_Terminates, "s0000_Incoming_2_Terminated_X_Terminates"), + // Incoming -> (Hangup) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Incoming, _fsm_action_hangup, _fsm_state_Terminated, s0000_Incoming_2_Terminated_X_Terminates, "s0000_Incoming_2_Terminated_X_Terminates"), + + /*======================= + * === Connected === + */ + // Connected -> (Register) -> Connected + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREGISTER, _fsm_cond_server_registering, _fsm_state_Connected, s0000_Connected_2_Connected_X_iREGISTER, "s0000_Connected_2_Connected_X_iREGISTER"), + // Connected -> (UnRegister) -> Terminated + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_iREGISTER, _fsm_cond_server_unregistering, _fsm_state_Terminated, s0000_Connected_2_Terminated_X_iREGISTER, "s0000_Connected_2_Terminated_X_iREGISTER"), + // Connected -> (TimedOut) -> Terminated + // Connected -> (Refresh OK) -> Connected + // Connected -> (Refresh NOK) -> Terminated + + TSK_FSM_ADD_NULL()); } @@ -113,125 +113,125 @@ int tsip_dialog_register_server_init(tsip_dialog_register_t *self) */ int s0000_Started_2_Terminated_X_iREGISTER(va_list *app) { - return 0; - /*tsip_dialog_register_t *self; - const tsip_action_t* action; + return 0; + /*tsip_dialog_register_t *self; + const tsip_action_t* action; - self = va_arg(*app, tsip_dialog_register_t *); - va_arg(*app, const tsip_message_t *); - action = va_arg(*app, const tsip_action_t *); + self = va_arg(*app, tsip_dialog_register_t *); + va_arg(*app, const tsip_message_t *); + action = va_arg(*app, const tsip_action_t *); - TSIP_DIALOG(self)->running = tsk_true; - tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); + TSIP_DIALOG(self)->running = tsk_true; + tsip_dialog_set_curr_action(TSIP_DIALOG(self), action); - // alert the user - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + // alert the user + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - return send_REGISTER(self, tsk_true);*/ + return send_REGISTER(self, tsk_true);*/ } /* Started -> (All is OK and we are Registering) -> Incoming */ int s0000_Started_2_Incoming_X_iREGISTER(va_list *app) { - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); - // set as server side dialog - TSIP_DIALOG_REGISTER(self)->is_server = tsk_true; + // set as server side dialog + TSIP_DIALOG_REGISTER(self)->is_server = tsk_true; - /* update last REGISTER */ - TSK_OBJECT_SAFE_FREE(self->last_iRegister); - self->last_iRegister = tsk_object_ref(request); + /* update last REGISTER */ + TSK_OBJECT_SAFE_FREE(self->last_iRegister); + self->last_iRegister = tsk_object_ref(request); - /* alert the user (session) */ - TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_i_newreg, - tsip_event_code_dialog_request_incoming, "Incoming New Register", request); + /* alert the user (session) */ + TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_i_newreg, + tsip_event_code_dialog_request_incoming, "Incoming New Register", request); - return 0; + return 0; } /* Incoming -> (Accept) -> Connected */ int s0000_Incoming_2_Connected_X_Accept(va_list *app) { - int ret; + int ret; - tsip_dialog_register_t *self; + tsip_dialog_register_t *self; - self = va_arg(*app, tsip_dialog_register_t *); + self = va_arg(*app, tsip_dialog_register_t *); - /* send 2xx OK */ - if((ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"))){ - return ret; - } + /* send 2xx OK */ + if((ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"))) { + return ret; + } - /* alert the user (dialog) */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + /* alert the user (dialog) */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - return ret; + return ret; } /* Incoming -> (Reject) -> Terminated */ int s0000_Incoming_2_Terminated_X_Terminates(va_list *app) { - int ret; - short code; - const char* phrase; - char* reason = tsk_null; - - tsip_dialog_register_t *self; - const tsip_action_t* action; - - self = va_arg(*app, tsip_dialog_register_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 : 600; - phrase = action->line_resp.phrase ? action->line_resp.phrase : "Not Supported"; - tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); - ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, code, phrase); - TSK_FREE(reason); - - return ret; + int ret; + short code; + const char* phrase; + char* reason = tsk_null; + + tsip_dialog_register_t *self; + const tsip_action_t* action; + + self = va_arg(*app, tsip_dialog_register_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 : 600; + phrase = action->line_resp.phrase ? action->line_resp.phrase : "Not Supported"; + tsk_sprintf(&reason, "SIP; cause=%hi; text=\"%s\"", code, phrase); + ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, code, phrase); + TSK_FREE(reason); + + return ret; } /* Connected -> (register) -> Connected */ static int s0000_Connected_2_Connected_X_iREGISTER(va_list *app) -{ - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); +{ + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - TSK_OBJECT_SAFE_FREE(self->last_iRegister); - self->last_iRegister = tsk_object_ref((tsk_object_t*)request); + TSK_OBJECT_SAFE_FREE(self->last_iRegister); + self->last_iRegister = tsk_object_ref((tsk_object_t*)request); - /* send 2xx OK */ - return tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"); + /* send 2xx OK */ + return tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"); } /* Connected -> (Unregister) -> Terminated */ int s0000_Connected_2_Terminated_X_iREGISTER(va_list *app) { - int ret; - tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); - tsip_request_t *request = va_arg(*app, tsip_request_t *); + int ret; + tsip_dialog_register_t *self = va_arg(*app, tsip_dialog_register_t *); + tsip_request_t *request = va_arg(*app, tsip_request_t *); - /* update last REGISTER */ - TSK_OBJECT_SAFE_FREE(self->last_iRegister); - self->last_iRegister = tsk_object_ref(request); + /* update last REGISTER */ + TSK_OBJECT_SAFE_FREE(self->last_iRegister); + self->last_iRegister = tsk_object_ref(request); - /* send 2xx OK */ - if((ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"))){ - return ret; - } + /* send 2xx OK */ + if((ret = tsip_dialog_register_send_RESPONSE(self, self->last_iRegister, 200, "OK"))) { + return ret; + } - /* alert the user (session) */ - TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_i_unregister, - tsip_event_code_dialog_request_incoming, "Incoming Request", request); + /* alert the user (session) */ + TSIP_DIALOG_REGISTER_SIGNAL(self, tsip_i_unregister, + tsip_event_code_dialog_request_incoming, "Incoming Request", request); - return 0; + return 0; } \ No newline at end of file diff --git a/tinySIP/src/dialogs/tsip_dialog_subscribe.client.c b/tinySIP/src/dialogs/tsip_dialog_subscribe.client.c index 28f34e4..89877de 100755 --- a/tinySIP/src/dialogs/tsip_dialog_subscribe.client.c +++ b/tinySIP/src/dialogs/tsip_dialog_subscribe.client.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop -* +* * 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. * @@ -77,66 +77,63 @@ static int tsip_dialog_subscribe_Any_2_Terminated_X_Error(va_list *app); /* ======================== conds ======================== */ static tsk_bool_t _fsm_cond_unsubscribing(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { - return dialog->unsubscribing; + return dialog->unsubscribing; } static tsk_bool_t _fsm_cond_subscribing(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { - return !_fsm_cond_unsubscribing(dialog, message); + return !_fsm_cond_unsubscribing(dialog, message); } static tsk_bool_t _fsm_cond_notify_terminated(tsip_dialog_subscribe_t* dialog, tsip_message_t* 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))) - { - return tsk_striequals(hdr_state->state, "terminated") && - (hdr_state->expires < 0 || tsk_striequals(hdr_state->reason, "rejected") || tsk_striequals(hdr_state->reason, "noresource")); - } - return tsk_false; + 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))) { + return tsk_striequals(hdr_state->state, "terminated") && + (hdr_state->expires < 0 || tsk_striequals(hdr_state->reason, "rejected") || tsk_striequals(hdr_state->reason, "noresource")); + } + return tsk_false; } static tsk_bool_t _fsm_cond_notify_not_terminated(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { - return !_fsm_cond_notify_terminated(dialog, message); + return !_fsm_cond_notify_terminated(dialog, message); } static tsk_bool_t _fsm_cond_silent_hangup(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { - return TSIP_DIALOG(dialog)->ss->silent_hangup; + return TSIP_DIALOG(dialog)->ss->silent_hangup; } static tsk_bool_t _fsm_cond_not_silent_hangup(tsip_dialog_subscribe_t* dialog, tsip_message_t* message) { - return !TSIP_DIALOG(dialog)->ss->silent_hangup; + return !TSIP_DIALOG(dialog)->ss->silent_hangup; } #define _fsm_cond_silent_shutdown _fsm_cond_silent_hangup #define _fsm_cond_not_silent_shutdown _fsm_cond_not_silent_hangup /* ======================== actions ======================== */ -typedef enum _fsm_action_e -{ - _fsm_action_subscribe = tsip_atype_subscribe, - _fsm_action_hangup = tsip_atype_hangup, - _fsm_action_cancel = tsip_atype_cancel, - _fsm_action_shutdown = tsip_atype_shutdown, - _fsm_action_transporterror = tsip_atype_transport_error, - - _fsm_action_1xx = 0xFF, - _fsm_action_2xx, - _fsm_action_401_407_421_494, - _fsm_action_423, - _fsm_action_300_to_699, - _fsm_action_shutdown_timedout, /* Any -> Terminated */ - _fsm_action_notify, - _fsm_action_error, +typedef enum _fsm_action_e { + _fsm_action_subscribe = tsip_atype_subscribe, + _fsm_action_hangup = tsip_atype_hangup, + _fsm_action_cancel = tsip_atype_cancel, + _fsm_action_shutdown = tsip_atype_shutdown, + _fsm_action_transporterror = tsip_atype_transport_error, + + _fsm_action_1xx = 0xFF, + _fsm_action_2xx, + _fsm_action_401_407_421_494, + _fsm_action_423, + _fsm_action_300_to_699, + _fsm_action_shutdown_timedout, /* Any -> Terminated */ + _fsm_action_notify, + _fsm_action_error, } _fsm_action_t; /* ======================== states ======================== */ -typedef enum _fsm_state_e -{ - _fsm_state_Started, - _fsm_state_Trying, - _fsm_state_Connected, - _fsm_state_Terminated +typedef enum _fsm_state_e { + _fsm_state_Started, + _fsm_state_Trying, + _fsm_state_Connected, + _fsm_state_Terminated } _fsm_state_t; @@ -144,188 +141,184 @@ _fsm_state_t; * Callback function called to alert the dialog for new events from the transaction/transport layers. * * @param [in,out] self A reference to the dialog. - * @param type The event type. - * @param [in,out] msg The incoming SIP/IMS message. + * @param type The event type. + * @param [in,out] msg The incoming SIP/IMS message. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_dialog_subscribe_event_callback(const tsip_dialog_subscribe_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 && 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)){ - 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); - } - else if(TSIP_RESPONSE_IS(msg,423)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); - } - else{ - // Alert User - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); - /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ - } - } - else{ - // - // REQUEST - // - if(TSIP_REQUEST_IS_NOTIFY(msg)){ - ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_notify, 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 && 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)) { + 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_IS(msg,401) || TSIP_RESPONSE_IS(msg,407) || TSIP_RESPONSE_IS(msg,421) || TSIP_RESPONSE_IS(msg,494)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_401_407_421_494, msg, action); + } + else if(TSIP_RESPONSE_IS(msg,423)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_423, msg, action); + } + else { + // Alert User + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_error, msg, action); + /* TSK_DEBUG_WARN("Not supported status code: %d", TSIP_RESPONSE_CODE(msg)); */ + } + } + else { + // + // REQUEST + // + if(TSIP_REQUEST_IS_NOTIFY(msg)) { + ret = tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_notify, 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; } /** Timer manager callback. * - * @param [in,out] self The owner of the signaled timer. + * @param [in,out] 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_subscribe_timer_callback(const tsip_dialog_subscribe_t* self, tsk_timer_id_t timer_id) { - int ret = -1; + int ret = -1; - if(self) - { - if(timer_id == self->timerrefresh.id){ - tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_subscribe, tsk_null, tsk_null); - ret = 0; - } - 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; + if(self) { + if(timer_id == self->timerrefresh.id) { + tsip_dialog_fsm_act(TSIP_DIALOG(self), _fsm_action_subscribe, tsk_null, tsk_null); + ret = 0; + } + 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_subscribe_t* tsip_dialog_subscribe_create(const tsip_ssession_handle_t* ss) { - return tsk_object_new(tsip_dialog_subscribe_def_t, ss); + return tsk_object_new(tsip_dialog_subscribe_def_t, ss); } /** Initializes the dialog. * - * @param [in,out] self The dialog to initialize. + * @param [in,out] self The dialog to initialize. **/ int tsip_dialog_subscribe_init(tsip_dialog_subscribe_t *self) -{ - /* Initialize the State Machine. */ - tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), - - /*======================= - * === Started === - */ - // Started -> (Send) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Started_2_Trying_X_subscribe, "tsip_dialog_subscribe_Started_2_Trying_X_subscribe"), - // Started -> (Any) -> Started - TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_subscribe_Started_2_Started_X_any"), - - - /*======================= - * === Trying === - */ - // Trying -> (1xx) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_1xx, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_1xx, "tsip_dialog_subscribe_Trying_2_Trying_X_1xx"), - // Trying -> (2xx) -> Terminated - TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_unsubscribing, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_2xx, "tsip_dialog_subscribe_Trying_2_Terminated_X_2xx"), - // Trying -> (2xx) -> Connected - TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_subscribing, _fsm_state_Connected, tsip_dialog_subscribe_Trying_2_Connected_X_2xx, "tsip_dialog_subscribe_Trying_2_Connected_X_2xx"), - // Trying -> (401/407/421/494) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_401_407_421_494, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494, "tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494"), - // Trying -> (423) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_423, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_423, "tsip_dialog_subscribe_Trying_2_Trying_X_423"), - // Trying -> (300_to_699) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699, "tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699"), - // Trying -> (cancel) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_cancel, "tsip_dialog_subscribe_Trying_2_Terminated_X_cancel"), - // Trying -> (Notify) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_notify, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY, "tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY"), - // Trying -> (hangup) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_hangup"), - // Trying -> (shutdown) -> Terminated - TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_shutdown"), - // Trying -> (Any) -> Trying - //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Trying, "tsip_dialog_subscribe_Trying_2_Trying_X_any"), - - - /*======================= - * === Connected === - */ - // Connected -> (SUBSCRIBE) -> Trying - TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Connected_2_Trying_X_subscribe, "tsip_dialog_subscribe_Connected_2_Trying_X_subscribe"), - // Connected -> (NOTIFY) -> Connected - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_not_terminated, _fsm_state_Connected, tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY"), - // Connected -> (NOTIFY) -> Terminated - TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_terminated, _fsm_state_Terminated, tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY"), - - /*======================= - * === Any === - */ - // Any -> (hangup) -> Trying - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_hangup, "tsip_dialog_subscribe_Any_2_Trying_X_hangup"), - // Any -> (silenthangup) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silenthangup"), - // Any -> (shutdown) -> Trying - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_shutdown, "tsip_dialog_subscribe_Any_2_Trying_X_shutdown"), - // Any -> (silentshutdown) -> Terminated - TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silentshutdown"), - // Any -> (shutdown timedout) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_shutdown_timedout"), - // Any -> (transport error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_transportError, "tsip_dialog_subscribe_Any_2_Terminated_X_transportError"), - // Any -> (error) -> Terminated - TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_Error, "tsip_dialog_subscribe_Any_2_Terminated_X_Error"), - - TSK_FSM_ADD_NULL()); - - /* Sets callback function */ - TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_subscribe_event_callback); - - /* Timers */ - self->timerrefresh.id = TSK_INVALID_TIMER_ID; - self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; - self->timershutdown.id = TSK_INVALID_TIMER_ID; - self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; - - return 0; +{ + /* Initialize the State Machine. */ + tsk_fsm_set(TSIP_DIALOG_GET_FSM(self), + + /*======================= + * === Started === + */ + // Started -> (Send) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Started_2_Trying_X_subscribe, "tsip_dialog_subscribe_Started_2_Trying_X_subscribe"), + // Started -> (Any) -> Started + TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Started, "tsip_dialog_subscribe_Started_2_Started_X_any"), + + + /*======================= + * === Trying === + */ + // Trying -> (1xx) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_1xx, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_1xx, "tsip_dialog_subscribe_Trying_2_Trying_X_1xx"), + // Trying -> (2xx) -> Terminated + TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_unsubscribing, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_2xx, "tsip_dialog_subscribe_Trying_2_Terminated_X_2xx"), + // Trying -> (2xx) -> Connected + TSK_FSM_ADD(_fsm_state_Trying, _fsm_action_2xx, _fsm_cond_subscribing, _fsm_state_Connected, tsip_dialog_subscribe_Trying_2_Connected_X_2xx, "tsip_dialog_subscribe_Trying_2_Connected_X_2xx"), + // Trying -> (401/407/421/494) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_401_407_421_494, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494, "tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494"), + // Trying -> (423) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_423, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_423, "tsip_dialog_subscribe_Trying_2_Trying_X_423"), + // Trying -> (300_to_699) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_300_to_699, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699, "tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699"), + // Trying -> (cancel) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_cancel, _fsm_state_Terminated, tsip_dialog_subscribe_Trying_2_Terminated_X_cancel, "tsip_dialog_subscribe_Trying_2_Terminated_X_cancel"), + // Trying -> (Notify) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_notify, _fsm_state_Trying, tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY, "tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY"), + // Trying -> (hangup) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_hangup"), + // Trying -> (shutdown) -> Terminated + TSK_FSM_ADD_ALWAYS(_fsm_state_Trying, _fsm_action_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Trying_2_Terminated_X_shutdown"), + // Trying -> (Any) -> Trying + //TSK_FSM_ADD_ALWAYS_NOTHING(_fsm_state_Trying, "tsip_dialog_subscribe_Trying_2_Trying_X_any"), + + + /*======================= + * === Connected === + */ + // Connected -> (SUBSCRIBE) -> Trying + TSK_FSM_ADD_ALWAYS(_fsm_state_Connected, _fsm_action_subscribe, _fsm_state_Trying, tsip_dialog_subscribe_Connected_2_Trying_X_subscribe, "tsip_dialog_subscribe_Connected_2_Trying_X_subscribe"), + // Connected -> (NOTIFY) -> Connected + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_not_terminated, _fsm_state_Connected, tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY"), + // Connected -> (NOTIFY) -> Terminated + TSK_FSM_ADD(_fsm_state_Connected, _fsm_action_notify, _fsm_cond_notify_terminated, _fsm_state_Terminated, tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY, "tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY"), + + /*======================= + * === Any === + */ + // Any -> (hangup) -> Trying + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_not_silent_hangup, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_hangup, "tsip_dialog_subscribe_Any_2_Trying_X_hangup"), + // Any -> (silenthangup) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_hangup, _fsm_cond_silent_hangup, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silenthangup"), + // Any -> (shutdown) -> Trying + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_not_silent_shutdown, _fsm_state_Trying, tsip_dialog_subscribe_Any_2_Trying_X_shutdown, "tsip_dialog_subscribe_Any_2_Trying_X_shutdown"), + // Any -> (silentshutdown) -> Terminated + TSK_FSM_ADD(tsk_fsm_state_any, _fsm_action_shutdown, _fsm_cond_silent_shutdown, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_Any_2_Trying_X_silentshutdown"), + // Any -> (shutdown timedout) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_shutdown_timedout, _fsm_state_Terminated, tsk_null, "tsip_dialog_subscribe_shutdown_timedout"), + // Any -> (transport error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_transporterror, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_transportError, "tsip_dialog_subscribe_Any_2_Terminated_X_transportError"), + // Any -> (error) -> Terminated + TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_error, _fsm_state_Terminated, tsip_dialog_subscribe_Any_2_Terminated_X_Error, "tsip_dialog_subscribe_Any_2_Terminated_X_Error"), + + TSK_FSM_ADD_NULL()); + + /* Sets callback function */ + TSIP_DIALOG(self)->callback = TSIP_DIALOG_EVENT_CALLBACK_F(tsip_dialog_subscribe_event_callback); + + /* Timers */ + self->timerrefresh.id = TSK_INVALID_TIMER_ID; + self->timerrefresh.timeout = TSIP_DIALOG(self)->expires; + self->timershutdown.id = TSK_INVALID_TIMER_ID; + self->timershutdown.timeout = TSIP_DIALOG_SHUTDOWN_TIMEOUT; + + return 0; } @@ -337,282 +330,282 @@ int tsip_dialog_subscribe_init(tsip_dialog_subscribe_t *self) */ int tsip_dialog_subscribe_Started_2_Trying_X_subscribe(va_list *app) { - tsip_dialog_subscribe_t *self; + tsip_dialog_subscribe_t *self; - self = va_arg(*app, tsip_dialog_subscribe_t *); + self = va_arg(*app, tsip_dialog_subscribe_t *); - TSIP_DIALOG(self)->running = tsk_true; + TSIP_DIALOG(self)->running = tsk_true; - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); - return send_SUBSCRIBE(self); + return send_SUBSCRIBE(self); } /* Trying -> (1xx) -> Trying */ int tsip_dialog_subscribe_Trying_2_Trying_X_1xx(va_list *app) { - /*tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *);*/ - /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ + /*tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *);*/ + /*const tsip_response_t *response = va_arg(*app, const tsip_response_t *);*/ - return 0; + return 0; } /* Trying -> (2xx) -> Terminated */ int tsip_dialog_subscribe_Trying_2_Terminated_X_2xx(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* Alert the user. */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user. */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Trying -> (2xx) -> Connected */ int tsip_dialog_subscribe_Trying_2_Connected_X_2xx(va_list *app) { - int ret; - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + int ret; + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); + tsk_bool_t first_time_to_connect = (TSIP_DIALOG(self)->state == tsip_initial); - /* Update the dialog state. */ - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - return ret; - } + /* Update the dialog state. */ + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + return ret; + } - /* Alert the user(session) */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - /* Alert the user(dialog) */ - if(first_time_to_connect){ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); - } + /* Alert the user(session) */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* Alert the user(dialog) */ + if(first_time_to_connect) { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connected, "Dialog connected"); + } - /* Reset current action */ - tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); + /* Reset current action */ + tsip_dialog_set_curr_action(TSIP_DIALOG(self), tsk_null); - /* Request timeout for dialog refresh (re-subscribtion). */ - self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); - TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(refresh); + /* Request timeout for dialog refresh (re-subscribtion). */ + self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), response); + TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(refresh); - return 0; + return 0; } /* Trying -> (401/407/421/494) -> Trying */ int tsip_dialog_subscribe_Trying_2_Trying_X_401_407_421_494(va_list *app) { - int ret; - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + int ret; + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + + if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))) { + /* Alert the user. */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - if((ret = tsip_dialog_update(TSIP_DIALOG(self), response))){ - /* Alert the user. */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - - return ret; - } - - return send_SUBSCRIBE(self); + return ret; + } + + return send_SUBSCRIBE(self); } /* Trying -> (423) -> Trying */ int tsip_dialog_subscribe_Trying_2_Trying_X_423(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - tsip_header_Min_Expires_t *hdr; + tsip_header_Min_Expires_t *hdr; - /* - RFC 3261 - 10.2.8 Error Responses + /* + RFC 3261 - 10.2.8 Error Responses - If a UA receives a 423 (Interval Too Brief) response, it MAY retry - the registration after making the expiration interval of all contact - addresses in the SUBSCRIBE request equal to or greater than the - expiration interval within the Min-Expires header field of the 423 - (Interval Too Brief) response. - */ - hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(response, tsip_htype_Min_Expires); - if(hdr){ - TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); - send_SUBSCRIBE(self); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_message_error, "Received invalid SIP response."); + If a UA receives a 423 (Interval Too Brief) response, it MAY retry + the registration after making the expiration interval of all contact + addresses in the SUBSCRIBE request equal to or greater than the + expiration interval within the Min-Expires header field of the 423 + (Interval Too Brief) response. + */ + hdr = (tsip_header_Min_Expires_t*)tsip_message_get_header(response, tsip_htype_Min_Expires); + if(hdr) { + TSIP_DIALOG(self)->expires = TSK_TIME_S_2_MS(hdr->value); + send_SUBSCRIBE(self); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_message_error, "Received invalid SIP response."); - return -1; - } + return -1; + } - return 0; + return 0; } /* Trying -> (300-699) -> Terminated */ int tsip_dialog_subscribe_Trying_2_Terminated_X_300_to_699(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - /* save last error */ - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + /* save last error */ + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - /* alert the user */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + /* alert the user */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - return 0; + return 0; } /* Trying -> (cancel) -> Terminated */ int tsip_dialog_subscribe_Trying_2_Terminated_X_cancel(va_list *app) { - int ret; - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - /* const tsip_response_t *response = va_arg(*app, const tsip_response_t *); */ + int ret; + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + /* const tsip_response_t *response = va_arg(*app, const tsip_response_t *); */ - /* Cancel all transactions associated to this dialog (will also be done when the dialog is destroyed (worth nothing)) */ - ret = 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)) */ + ret = tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, TSIP_DIALOG(self)); - /* 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. + */ - /* alert the user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Subscription cancelled"); + /* alert the user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_request_cancelled, "Subscription cancelled"); - return ret; + return ret; } /* Trying -> (NOTIFY) -> Trying */ int tsip_dialog_subscribe_Trying_2_Trying_X_NOTIFY(va_list *app) { - int ret; - - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + int ret; + + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - ret = send_200NOTIFY(self, request); - ret = process_i_notify(self, request); - - return ret; + ret = send_200NOTIFY(self, request); + ret = process_i_notify(self, request); + + return ret; } /* Connected -> (SUBSCRIBE) -> Trying */ int tsip_dialog_subscribe_Connected_2_Trying_X_subscribe(va_list *app) { - tsip_dialog_subscribe_t *self; + tsip_dialog_subscribe_t *self; - self = va_arg(*app, tsip_dialog_subscribe_t *); + self = va_arg(*app, tsip_dialog_subscribe_t *); - return send_SUBSCRIBE(self); + return send_SUBSCRIBE(self); } /* Connected -> (NOTIFY) -> Connected */ int tsip_dialog_subscribe_Connected_2_Connected_X_NOTIFY(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - int ret; + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + int ret; - ret = send_200NOTIFY(self, request); - ret = process_i_notify(self, request); + ret = send_200NOTIFY(self, request); + ret = process_i_notify(self, request); - return ret; + return ret; } /* Connected -> (NOTIFY) -> Terminated */ int tsip_dialog_subscribe_Connected_2_Terminated_X_NOTIFY(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_request_t *request = va_arg(*app, const tsip_request_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_request_t *request = va_arg(*app, const tsip_request_t *); - /* Alert the user */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, tsip_i_notify, - tsip_event_code_dialog_request_incoming, "Incoming NOTIFY.", request); + /* Alert the user */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, tsip_i_notify, + tsip_event_code_dialog_request_incoming, "Incoming NOTIFY.", request); - return send_200NOTIFY(self, request); + return send_200NOTIFY(self, request); } /* Any -> (hangup) -> Trying */ int tsip_dialog_subscribe_Any_2_Trying_X_hangup(va_list *app) { - tsip_dialog_subscribe_t *self; + tsip_dialog_subscribe_t *self; - self = va_arg(*app, tsip_dialog_subscribe_t *); + self = va_arg(*app, tsip_dialog_subscribe_t *); - /* 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"); - self->unsubscribing = tsk_true; - return send_SUBSCRIBE(self); + self->unsubscribing = tsk_true; + return send_SUBSCRIBE(self); } /* Any -> (shutdown) -> Trying */ int tsip_dialog_subscribe_Any_2_Trying_X_shutdown(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - /* schedule shutdow timeout */ - TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(shutdown); + /* schedule shutdow timeout */ + TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(shutdown); - /* alert user */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); + /* alert user */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_terminating, "Terminating dialog"); - self->unsubscribing = tsk_true; - return send_SUBSCRIBE(self); + self->unsubscribing = tsk_true; + return send_SUBSCRIBE(self); } /* Any -> (transport error) -> Terminated */ int tsip_dialog_subscribe_Any_2_Terminated_X_transportError(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - /* const tsip_response_t *response = va_arg(*app, const tsip_response_t *); */ + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + /* const tsip_response_t *response = va_arg(*app, const tsip_response_t *); */ - /* Alert the user. */ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); + /* Alert the user. */ + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_transport_error, "Transport error."); - return 0; + return 0; } /* Any -> (error) -> Terminated */ int tsip_dialog_subscribe_Any_2_Terminated_X_Error(va_list *app) { - tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); - const tsip_response_t *response = va_arg(*app, const tsip_response_t *); + tsip_dialog_subscribe_t *self = va_arg(*app, tsip_dialog_subscribe_t *); + const tsip_response_t *response = va_arg(*app, const tsip_response_t *); - // save last error - tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); + // save last error + tsip_dialog_set_lasterror_2(TSIP_DIALOG(self), TSIP_RESPONSE_PHRASE(response), TSIP_RESPONSE_CODE(response), response); - /* Alert user */ - if(response){ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, - TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); - } - else{ - TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); - } + /* Alert user */ + if(response) { + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, self->unsubscribing ? tsip_ao_unsubscribe : tsip_ao_subscribe, + TSIP_RESPONSE_CODE(response), TSIP_RESPONSE_PHRASE(response), response); + } + else { + TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_global_error, "Global error."); + } - return 0; + return 0; } @@ -621,63 +614,63 @@ int tsip_dialog_subscribe_Any_2_Terminated_X_Error(va_list *app) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++ /** - * Sends a SUBSCRIBE request. + * Sends a SUBSCRIBE request. * * @param [in,out] self The caller. * - * @return Zero if succeed and non-zero error code otherwise. + * @return Zero if succeed and non-zero error code otherwise. **/ int send_SUBSCRIBE(tsip_dialog_subscribe_t *self) { - tsip_request_t *request; - int ret = -1; - - if(self->unsubscribing){ - TSIP_DIALOG(self)->expires = 0; - } + tsip_request_t *request; + int ret = -1; + + if(self->unsubscribing) { + TSIP_DIALOG(self)->expires = 0; + } - if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "SUBSCRIBE"))){ - /* apply action params to the request */ - if(TSIP_DIALOG(self)->curr_action){ - tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); - } - /* send the request */ - ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); - TSK_OBJECT_SAFE_FREE(request); - } + if((request = tsip_dialog_request_new(TSIP_DIALOG(self), "SUBSCRIBE"))) { + /* apply action params to the request */ + if(TSIP_DIALOG(self)->curr_action) { + tsip_dialog_apply_action(request, TSIP_DIALOG(self)->curr_action); + } + /* send the request */ + ret = tsip_dialog_request_send(TSIP_DIALOG(self), request); + TSK_OBJECT_SAFE_FREE(request); + } - return ret; + return ret; } int send_200NOTIFY(tsip_dialog_subscribe_t *self, const tsip_request_t* request) { - tsip_response_t *response; - int ret = -1; + tsip_response_t *response; + int ret = -1; - if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))){ - ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); - TSK_OBJECT_SAFE_FREE(response); - } - return ret; + if((response = tsip_dialog_response_new(TSIP_DIALOG(self), 200, "OK", request))) { + ret = tsip_dialog_response_send(TSIP_DIALOG(self), response); + TSK_OBJECT_SAFE_FREE(response); + } + return ret; } // process incoming notify: refresh delay and alert the user int process_i_notify(tsip_dialog_subscribe_t *self, const tsip_request_t* notify) { - if(!self || !notify){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* Request timeout for dialog refresh (re-registration). */ - self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), notify); - TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(refresh); - - /* Alert the user */ - TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, tsip_i_notify, - tsip_event_code_dialog_request_incoming, "Incoming NOTIFY.", notify); - - return 0; + if(!self || !notify) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + /* Request timeout for dialog refresh (re-registration). */ + self->timerrefresh.timeout = tsip_dialog_get_newdelay(TSIP_DIALOG(self), notify); + TSIP_DIALOG_SUBSCRIBE_TIMER_SCHEDULE(refresh); + + /* Alert the user */ + TSIP_DIALOG_SUBSCRIBE_SIGNAL(self, tsip_i_notify, + tsip_event_code_dialog_request_incoming, "Incoming NOTIFY.", notify); + + return 0; } /** @@ -687,15 +680,15 @@ int process_i_notify(tsip_dialog_subscribe_t *self, const tsip_request_t* notify **/ int tsip_dialog_subscribe_OnTerminated(tsip_dialog_subscribe_t *self) { - TSK_DEBUG_INFO("=== SUBSCRIBE Dialog terminated ==="); + TSK_DEBUG_INFO("=== SUBSCRIBE Dialog terminated ==="); - /* 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 : "Dialog terminated", - TSIP_DIALOG(self)->last_error.message); + /* 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 : "Dialog terminated", + TSIP_DIALOG(self)->last_error.message); - /* Remove from the dialog layer. */ - return tsip_dialog_remove(TSIP_DIALOG(self)); + /* Remove from the dialog layer. */ + return tsip_dialog_remove(TSIP_DIALOG(self)); } @@ -716,49 +709,48 @@ int tsip_dialog_subscribe_OnTerminated(tsip_dialog_subscribe_t *self) // static tsk_object_t* tsip_dialog_subscribe_ctor(tsk_object_t * self, va_list * app) { - tsip_dialog_subscribe_t *dialog = self; - if(dialog){ - tsip_ssession_handle_t *ss = va_arg(*app, tsip_ssession_handle_t *); + tsip_dialog_subscribe_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_SUBSCRIBE, tsk_null, ss, _fsm_state_Started, _fsm_state_Terminated); + /* Initialize base class */ + tsip_dialog_init(TSIP_DIALOG(self), tsip_dialog_SUBSCRIBE, 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_subscribe_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_subscribe_OnTerminated), (const void*)dialog); - /* Initialize the class itself */ - tsip_dialog_subscribe_init(self); - } - return self; + /* Initialize the class itself */ + tsip_dialog_subscribe_init(self); + } + return self; } static tsk_object_t* tsip_dialog_subscribe_dtor(tsk_object_t * _self) -{ - tsip_dialog_subscribe_t *self = _self; - if(self){ - /* Cancel all timers */ - TSIP_DIALOG_TIMER_CANCEL(refresh); - TSIP_DIALOG_TIMER_CANCEL(shutdown); +{ + tsip_dialog_subscribe_t *self = _self; + if(self) { + /* Cancel all timers */ + TSIP_DIALOG_TIMER_CANCEL(refresh); + TSIP_DIALOG_TIMER_CANCEL(shutdown); - /* DeInitialize base class (will cancel all transactions) */ - tsip_dialog_deinit(TSIP_DIALOG(self)); + /* DeInitialize base class (will cancel all transactions) */ + tsip_dialog_deinit(TSIP_DIALOG(self)); - TSK_DEBUG_INFO("*** SUBSCRIBE Dialog destroyed ***"); - } - return self; + TSK_DEBUG_INFO("*** SUBSCRIBE Dialog destroyed ***"); + } + return self; } static int tsip_dialog_subscribe_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_subscribe_def_s = -{ - sizeof(tsip_dialog_subscribe_t), - tsip_dialog_subscribe_ctor, - tsip_dialog_subscribe_dtor, - tsip_dialog_subscribe_cmp, +static const tsk_object_def_t tsip_dialog_subscribe_def_s = { + sizeof(tsip_dialog_subscribe_t), + tsip_dialog_subscribe_ctor, + tsip_dialog_subscribe_dtor, + tsip_dialog_subscribe_cmp, }; const tsk_object_def_t *tsip_dialog_subscribe_def_t = &tsip_dialog_subscribe_def_s; -- cgit v1.1