summaryrefslogtreecommitdiffstats
path: root/tinySIP/src/dialogs/tsip_dialog.c
diff options
context:
space:
mode:
authorMamadou DIOP <bossiel@yahoo.fr>2016-02-23 22:00:35 +0100
committerMamadou DIOP <bossiel@yahoo.fr>2016-02-23 22:00:35 +0100
commit50dfb4359619563012997bc3ddafb7667741066c (patch)
treedb234c1edc3240a653363b5735fc4077af4b8720 /tinySIP/src/dialogs/tsip_dialog.c
parent94b2219209038e05dd26395f6fb700be4d1062c0 (diff)
downloaddoubango-50dfb4359619563012997bc3ddafb7667741066c.zip
doubango-50dfb4359619563012997bc3ddafb7667741066c.tar.gz
Add new QoS implementation
Code formatting
Diffstat (limited to 'tinySIP/src/dialogs/tsip_dialog.c')
-rwxr-xr-xtinySIP/src/dialogs/tsip_dialog.c2239
1 files changed, 1113 insertions, 1126 deletions
diff --git a/tinySIP/src/dialogs/tsip_dialog.c b/tinySIP/src/dialogs/tsip_dialog.c
index 13dcdf4..3f23f0e 100755
--- a/tinySIP/src/dialogs/tsip_dialog.c
+++ b/tinySIP/src/dialogs/tsip_dialog.c
@@ -2,19 +2,19 @@
* Copyright (C) 2010-2011 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
-*
+*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
-*
+*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-*
+*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
@@ -87,363 +87,361 @@ extern tsip_uri_t* tsip_stack_get_contacturi(const tsip_stack_t *self, const cha
tsip_request_t *tsip_dialog_request_new(const tsip_dialog_t *self, const char* method)
{
- tsip_request_t *request = tsk_null;
- tsip_uri_t *to_uri, *from_uri, *request_uri;
- const char *call_id;
- int copy_routes_start = -1; /* NONE */
- const tsk_list_item_t* item;
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- The Call-ID of the request MUST be set to the Call-ID of the dialog.
- */
- call_id = self->callid;
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- Requests within a dialog MUST contain strictly monotonically
- increasing and contiguous CSeq sequence numbers (increasing-by-one)
- in each direction (excepting ACK and CANCEL of course, whose numbers
- equal the requests being acknowledged or cancelled). Therefore, if
- the local sequence number is not empty, the value of the local
- sequence number MUST be incremented by one, and this value MUST be
- placed into the CSeq header field.
- */
- /*if(!tsk_striequals(method, "ACK") && !tsk_striequals(method, "CANCEL"))
- {
- TSIP_DIALOG(self)->cseq_value +=1;
- }
- ===> See send method (cseq will be incremented before sending the request)
- */
-
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- The URI in the To field of the request MUST be set to the remote URI
- from the dialog state. The tag in the To header field of the request
- MUST be set to the remote tag of the dialog ID. The From URI of the
- request MUST be set to the local URI from the dialog state. The tag
- in the From header field of the request MUST be set to the local tag
- of the dialog ID. If the value of the remote or local tags is null,
- the tag parameter MUST be omitted from the To or From header fields,
- respectively.
- */
- to_uri = tsk_object_ref((void*)self->uri_remote);
- from_uri = tsk_object_ref((void*)self->uri_local);
-
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- If the route set is empty, the UAC MUST place the remote target URI
- into the Request-URI. The UAC MUST NOT add a Route header field to
- the request.
- */
- if(TSK_LIST_IS_EMPTY(self->record_routes)){
- request_uri = tsk_object_ref((void*)self->uri_remote_target);
- }
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- If the route set is not empty, and the first URI in the route set
- contains the lr parameter (see Section 19.1.1), the UAC MUST place
- the remote target URI into the Request-URI and MUST include a Route
- header field containing the route set values in order, including all
- parameters.
-
- If the route set is not empty, and its first URI does not contain the
- lr parameter, the UAC MUST place the first URI from the route set
- into the Request-URI, stripping any parameters that are not allowed
- in a Request-URI. The UAC MUST add a Route header field containing
- the remainder of the route set values in order, including all
- parameters. The UAC MUST then place the remote target URI into the
- Route header field as the last value.
-
- For example, if the remote target is sip:user@remoteua and the route
- set contains:
-
- <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>
- */
- else{
- const tsip_uri_t *first_route = ((tsip_header_Record_Route_t*)TSK_LIST_FIRST_DATA(self->record_routes))->uri;
- if(tsk_params_have_param(first_route->params, "lr")){
- request_uri = tsk_object_ref(self->uri_remote_target);
- copy_routes_start = 0; /* Copy all */
- }
- else{
- request_uri = tsk_object_ref((void*)first_route);
- copy_routes_start = 1; /* Copy starting at index 1. */
- }
- }
-
- /*=====================================================================
- */
- request = tsip_request_new(method, request_uri, from_uri, to_uri, call_id, self->cseq_value);
- request->To->tag = tsk_strdup(self->tag_remote);
- request->From->tag = tsk_strdup(self->tag_local);
- request->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact, SigComp, IPSec, ...) */
-
-
- /*
- RFC 3261 - 12.2.1.1 Generating the Request
-
- A UAC SHOULD include a Contact header field in any target refresh
- requests within a dialog, and unless there is a need to change it,
- the URI SHOULD be the same as used in previous requests within the
- dialog. If the "secure" flag is true, that URI MUST be a SIPS URI.
- As discussed in Section 12.2.2, a Contact header field in a target
- refresh request updates the remote target URI. This allows a UA to
- provide a new contact address, should its address change during the
- duration of the dialog.
- */
- switch(request->line.request.request_type){
- case tsip_MESSAGE:
- case tsip_PUBLISH:
- case tsip_BYE:
- {
- if(request->line.request.request_type == tsip_PUBLISH) {
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires)));
- }
- /* add caps in Accept-Contact headers */
- tsk_list_foreach(item, self->ss->caps) {
- const tsk_param_t* param = TSK_PARAM(item->data);
- char* value = tsk_null;
- tsk_sprintf(&value, "*;%s%s%s",
- param->name,
- param->value ? "=" : "",
- param->value ? param->value : "");
- if(value) {
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Accept-Contact", value));
- TSK_FREE(value);
- }
- }
- break;
- }
-
- default:
- {
- char* contact = tsk_null;
- tsip_header_Contacts_L_t *hdr_contacts;
-
- if(request->line.request.request_type == tsip_OPTIONS ||
- request->line.request.request_type == tsip_PUBLISH ||
- request->line.request.request_type == tsip_REGISTER){
- /**** with expires */
- tsk_sprintf(&contact, "m: <%s:%s@%s:%d>;expires=%d\r\n",
- "sip",
- from_uri->user_name,
- "127.0.0.1",
- 5060,
-
- TSK_TIME_MS_2_S(self->expires));
- }
- else{
- /**** without expires */
- if(request->line.request.request_type == tsip_SUBSCRIBE){
- /* RFC 3265 - 3.1.1. Subscription Duration
- An "expires" parameter on the "Contact" header has no semantics for SUBSCRIBE and is explicitly
- not equivalent to an "Expires" header in a SUBSCRIBE request or response.
- */
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires)));
- }
- tsk_sprintf(&contact, "m: <%s:%s@%s:%d%s%s%s%s%s%s%s%s%s>\r\n",
- "sip",
- from_uri->user_name,
- "127.0.0.1",
- 5060,
-
- self->ss->ws.src.host ? ";" : "",
- self->ss->ws.src.host ? "ws-src-ip=" : "",
- self->ss->ws.src.host ? self->ss->ws.src.host : "",
- self->ss->ws.src.port[0] ? ";" : "",
- self->ss->ws.src.port[0] ? "ws-src-port=" : "",
- self->ss->ws.src.port[0] ? self->ss->ws.src.port : "",
- self->ss->ws.src.proto ? ";" : "",
- self->ss->ws.src.proto ? "ws-src-proto=" : "",
- self->ss->ws.src.proto ? self->ss->ws.src.proto : ""
- );
- }
- hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact));
- if(!TSK_LIST_IS_EMPTY(hdr_contacts)){
- request->Contact = tsk_object_ref(hdr_contacts->head->data);
- }
- TSK_OBJECT_SAFE_FREE(hdr_contacts);
- TSK_FREE(contact);
-
- /* Add capabilities as per RFC 3840 */
- if(request->Contact) {
- tsk_list_foreach(item, self->ss->caps){
- tsk_params_add_param(&TSIP_HEADER(request->Contact)->params, TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value);
- }
- }
-
- break;
- }
- }
-
- /* Update authorizations */
- if(self->state == tsip_initial && TSK_LIST_IS_EMPTY(self->challenges)){
- /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE
- On sending a REGISTER request in order to indicate support for early IMS security procedures, the UE shall not
- include an Authorization header field and not include header fields or header field values as required by RFC3329.
- */
- if(TSIP_REQUEST_IS_REGISTER(request) && !TSIP_DIALOG_GET_STACK(self)->security.earlyIMS){
- /* 3GPP TS 24.229 - 5.1.1.2.2 Initial registration using IMS AKA
- On sending a REGISTER request, the UE shall populate the header fields as follows:
- a) an Authorization header field, with:
- - the "username" header field parameter, set to the value of the private user identity;
- - the "realm" header field parameter, set to the domain name of the home network;
- - the "uri" header field parameter, set to the SIP URI of the domain name of the home network;
- - the "nonce" header field parameter, set to an empty value; and
- - the "response" header field parameter, set to an empty value;
- */
- const char* realm = TSIP_DIALOG_GET_STACK(self)->network.realm ? TSIP_DIALOG_GET_STACK(self)->network.realm->host : "(null)";
- char* request_uri = tsip_uri_tostring(request->line.request.uri, tsk_false, tsk_false);
- tsip_header_t* auth_hdr = tsip_challenge_create_empty_header_authorization(TSIP_DIALOG_GET_STACK(self)->identity.impi, realm, request_uri);
- tsip_message_add_header(request, auth_hdr);
- tsk_object_unref(auth_hdr), auth_hdr = tsk_null;
- TSK_FREE(request_uri);
- }
- }
- else if(!TSK_LIST_IS_EMPTY(self->challenges)){
- tsip_challenge_t *challenge;
- tsip_header_t* auth_hdr;
- tsk_list_foreach(item, self->challenges){
- challenge = item->data;
- auth_hdr = tsip_challenge_create_header_authorization(challenge, request);
- if(auth_hdr){
- tsip_message_add_header(request, auth_hdr);
- tsk_object_unref(auth_hdr), auth_hdr = tsk_null;
- }
- }
- }
-
- /* Update CSeq */
- /* RFC 3261 - 13.2.2.4 2xx Responses
- Generating ACK: The sequence number of the CSeq header field MUST be
- the same as the INVITE being acknowledged, but the CSeq method MUST
- be ACK. The ACK MUST contain the same credentials as the INVITE. If
- the 2xx contains an offer (based on the rules above), the ACK MUST
- carry an answer in its body.
- ==> CSeq number will be added/updated by the caller of this function,
- credentials were added above.
- */
- if(!TSIP_REQUEST_IS_ACK(request) && !TSIP_REQUEST_IS_CANCEL(request)){
- request->CSeq->seq = ++(TSIP_DIALOG(self)->cseq_value);
- }
-
- /* Route generation
- * ==> http://betelco.blogspot.com/2008/11/proxy-and-service-route-discovery-in.html
- * The dialog Routes have been copied above.
-
- 3GPP TS 24.229 - 5.1.2A.1 UE-originating case
-
- The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE
- shall build a list of Route header field values made out of the following, in this order:
- a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and
- b) the P-CSCF port based on the security mechanism in use:
-
- - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during
- the registration procedure;
- - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in
- use as a security mechanism, the unprotected server port used during the registration procedure;
- c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last
- registration or re-registration of the public user identity with associated contact address.
- */
- if(!TSIP_REQUEST_IS_REGISTER(request))
- { // According to the above link ==> Initial/Re/De registration do not have routes.
- if(copy_routes_start != -1)
- { /* The dialog already have routes ==> copy them. */
- if(self->state == tsip_early || self->state == tsip_established){
- int32_t index = -1;
- tsk_list_foreach(item, self->record_routes){
- tsip_header_Record_Route_t *record_Route = ((tsip_header_Record_Route_t*)item->data);
- const tsip_uri_t* uri = record_Route->uri;
- tsip_header_Route_t *route = tsk_null;
- if(++index < copy_routes_start || !uri){
- continue;
- }
-
- if((route = tsip_header_Route_create(uri))){
- // copy parameters: see http://code.google.com/p/imsdroid/issues/detail?id=52
- if(!TSK_LIST_IS_EMPTY(TSIP_HEADER_PARAMS(record_Route))){
- if(!TSIP_HEADER_PARAMS(route)){
- TSIP_HEADER_PARAMS(route) = tsk_list_create();
- }
- tsk_list_pushback_list(TSIP_HEADER_PARAMS(route), TSIP_HEADER_PARAMS(record_Route));
- }
-
- tsip_message_add_header(request, TSIP_HEADER(route));
- TSK_OBJECT_SAFE_FREE(route);
- }
- }
- }
- }
- else
- { /* No routes associated to this dialog. */
- if(self->state == tsip_initial || self->state == tsip_early){
- /* GPP TS 24.229 section 5.1.2A [Generic procedures applicable to all methods excluding the REGISTER method]:
- The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE
- shall build a list of Route header field values made out of the following, in this order:
- a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and
- b) the P-CSCF port based on the security mechanism in use:
- - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during
- the registration procedure;
- - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in
- use as a security mechanism, the unprotected server port used during the registration procedure;
- c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last
- registration or re-registration of the public user identity with associated contact address.
- */
+ tsip_request_t *request = tsk_null;
+ tsip_uri_t *to_uri, *from_uri, *request_uri;
+ const char *call_id;
+ int copy_routes_start = -1; /* NONE */
+ const tsk_list_item_t* item;
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ The Call-ID of the request MUST be set to the Call-ID of the dialog.
+ */
+ call_id = self->callid;
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ Requests within a dialog MUST contain strictly monotonically
+ increasing and contiguous CSeq sequence numbers (increasing-by-one)
+ in each direction (excepting ACK and CANCEL of course, whose numbers
+ equal the requests being acknowledged or cancelled). Therefore, if
+ the local sequence number is not empty, the value of the local
+ sequence number MUST be incremented by one, and this value MUST be
+ placed into the CSeq header field.
+ */
+ /*if(!tsk_striequals(method, "ACK") && !tsk_striequals(method, "CANCEL"))
+ {
+ TSIP_DIALOG(self)->cseq_value +=1;
+ }
+ ===> See send method (cseq will be incremented before sending the request)
+ */
+
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ The URI in the To field of the request MUST be set to the remote URI
+ from the dialog state. The tag in the To header field of the request
+ MUST be set to the remote tag of the dialog ID. The From URI of the
+ request MUST be set to the local URI from the dialog state. The tag
+ in the From header field of the request MUST be set to the local tag
+ of the dialog ID. If the value of the remote or local tags is null,
+ the tag parameter MUST be omitted from the To or From header fields,
+ respectively.
+ */
+ to_uri = tsk_object_ref((void*)self->uri_remote);
+ from_uri = tsk_object_ref((void*)self->uri_local);
+
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ If the route set is empty, the UAC MUST place the remote target URI
+ into the Request-URI. The UAC MUST NOT add a Route header field to
+ the request.
+ */
+ if(TSK_LIST_IS_EMPTY(self->record_routes)) {
+ request_uri = tsk_object_ref((void*)self->uri_remote_target);
+ }
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ If the route set is not empty, and the first URI in the route set
+ contains the lr parameter (see Section 19.1.1), the UAC MUST place
+ the remote target URI into the Request-URI and MUST include a Route
+ header field containing the route set values in order, including all
+ parameters.
+
+ If the route set is not empty, and its first URI does not contain the
+ lr parameter, the UAC MUST place the first URI from the route set
+ into the Request-URI, stripping any parameters that are not allowed
+ in a Request-URI. The UAC MUST add a Route header field containing
+ the remainder of the route set values in order, including all
+ parameters. The UAC MUST then place the remote target URI into the
+ Route header field as the last value.
+
+ For example, if the remote target is sip:user@remoteua and the route
+ set contains:
+
+ <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4>
+ */
+ else {
+ const tsip_uri_t *first_route = ((tsip_header_Record_Route_t*)TSK_LIST_FIRST_DATA(self->record_routes))->uri;
+ if(tsk_params_have_param(first_route->params, "lr")) {
+ request_uri = tsk_object_ref(self->uri_remote_target);
+ copy_routes_start = 0; /* Copy all */
+ }
+ else {
+ request_uri = tsk_object_ref((void*)first_route);
+ copy_routes_start = 1; /* Copy starting at index 1. */
+ }
+ }
+
+ /*=====================================================================
+ */
+ request = tsip_request_new(method, request_uri, from_uri, to_uri, call_id, self->cseq_value);
+ request->To->tag = tsk_strdup(self->tag_remote);
+ request->From->tag = tsk_strdup(self->tag_local);
+ request->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact, SigComp, IPSec, ...) */
+
+
+ /*
+ RFC 3261 - 12.2.1.1 Generating the Request
+
+ A UAC SHOULD include a Contact header field in any target refresh
+ requests within a dialog, and unless there is a need to change it,
+ the URI SHOULD be the same as used in previous requests within the
+ dialog. If the "secure" flag is true, that URI MUST be a SIPS URI.
+ As discussed in Section 12.2.2, a Contact header field in a target
+ refresh request updates the remote target URI. This allows a UA to
+ provide a new contact address, should its address change during the
+ duration of the dialog.
+ */
+ switch(request->line.request.request_type) {
+ case tsip_MESSAGE:
+ case tsip_PUBLISH:
+ case tsip_BYE: {
+ if(request->line.request.request_type == tsip_PUBLISH) {
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires)));
+ }
+ /* add caps in Accept-Contact headers */
+ tsk_list_foreach(item, self->ss->caps) {
+ const tsk_param_t* param = TSK_PARAM(item->data);
+ char* value = tsk_null;
+ tsk_sprintf(&value, "*;%s%s%s",
+ param->name,
+ param->value ? "=" : "",
+ param->value ? param->value : "");
+ if(value) {
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_DUMMY_VA_ARGS("Accept-Contact", value));
+ TSK_FREE(value);
+ }
+ }
+ break;
+ }
+
+ default: {
+ char* contact = tsk_null;
+ tsip_header_Contacts_L_t *hdr_contacts;
+
+ if(request->line.request.request_type == tsip_OPTIONS ||
+ request->line.request.request_type == tsip_PUBLISH ||
+ request->line.request.request_type == tsip_REGISTER) {
+ /**** with expires */
+ tsk_sprintf(&contact, "m: <%s:%s@%s:%d>;expires=%d\r\n",
+ "sip",
+ from_uri->user_name,
+ "127.0.0.1",
+ 5060,
+
+ TSK_TIME_MS_2_S(self->expires));
+ }
+ else {
+ /**** without expires */
+ if(request->line.request.request_type == tsip_SUBSCRIBE) {
+ /* RFC 3265 - 3.1.1. Subscription Duration
+ An "expires" parameter on the "Contact" header has no semantics for SUBSCRIBE and is explicitly
+ not equivalent to an "Expires" header in a SUBSCRIBE request or response.
+ */
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_EXPIRES_VA_ARGS(TSK_TIME_MS_2_S(self->expires)));
+ }
+ tsk_sprintf(&contact, "m: <%s:%s@%s:%d%s%s%s%s%s%s%s%s%s>\r\n",
+ "sip",
+ from_uri->user_name,
+ "127.0.0.1",
+ 5060,
+
+ self->ss->ws.src.host ? ";" : "",
+ self->ss->ws.src.host ? "ws-src-ip=" : "",
+ self->ss->ws.src.host ? self->ss->ws.src.host : "",
+ self->ss->ws.src.port[0] ? ";" : "",
+ self->ss->ws.src.port[0] ? "ws-src-port=" : "",
+ self->ss->ws.src.port[0] ? self->ss->ws.src.port : "",
+ self->ss->ws.src.proto ? ";" : "",
+ self->ss->ws.src.proto ? "ws-src-proto=" : "",
+ self->ss->ws.src.proto ? self->ss->ws.src.proto : ""
+ );
+ }
+ hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact));
+ if(!TSK_LIST_IS_EMPTY(hdr_contacts)) {
+ request->Contact = tsk_object_ref(hdr_contacts->head->data);
+ }
+ TSK_OBJECT_SAFE_FREE(hdr_contacts);
+ TSK_FREE(contact);
+
+ /* Add capabilities as per RFC 3840 */
+ if(request->Contact) {
+ tsk_list_foreach(item, self->ss->caps) {
+ tsk_params_add_param(&TSIP_HEADER(request->Contact)->params, TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value);
+ }
+ }
+
+ break;
+ }
+ }
+
+ /* Update authorizations */
+ if(self->state == tsip_initial && TSK_LIST_IS_EMPTY(self->challenges)) {
+ /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE
+ On sending a REGISTER request in order to indicate support for early IMS security procedures, the UE shall not
+ include an Authorization header field and not include header fields or header field values as required by RFC3329.
+ */
+ if(TSIP_REQUEST_IS_REGISTER(request) && !TSIP_DIALOG_GET_STACK(self)->security.earlyIMS) {
+ /* 3GPP TS 24.229 - 5.1.1.2.2 Initial registration using IMS AKA
+ On sending a REGISTER request, the UE shall populate the header fields as follows:
+ a) an Authorization header field, with:
+ - the "username" header field parameter, set to the value of the private user identity;
+ - the "realm" header field parameter, set to the domain name of the home network;
+ - the "uri" header field parameter, set to the SIP URI of the domain name of the home network;
+ - the "nonce" header field parameter, set to an empty value; and
+ - the "response" header field parameter, set to an empty value;
+ */
+ const char* realm = TSIP_DIALOG_GET_STACK(self)->network.realm ? TSIP_DIALOG_GET_STACK(self)->network.realm->host : "(null)";
+ char* request_uri = tsip_uri_tostring(request->line.request.uri, tsk_false, tsk_false);
+ tsip_header_t* auth_hdr = tsip_challenge_create_empty_header_authorization(TSIP_DIALOG_GET_STACK(self)->identity.impi, realm, request_uri);
+ tsip_message_add_header(request, auth_hdr);
+ tsk_object_unref(auth_hdr), auth_hdr = tsk_null;
+ TSK_FREE(request_uri);
+ }
+ }
+ else if(!TSK_LIST_IS_EMPTY(self->challenges)) {
+ tsip_challenge_t *challenge;
+ tsip_header_t* auth_hdr;
+ tsk_list_foreach(item, self->challenges) {
+ challenge = item->data;
+ auth_hdr = tsip_challenge_create_header_authorization(challenge, request);
+ if(auth_hdr) {
+ tsip_message_add_header(request, auth_hdr);
+ tsk_object_unref(auth_hdr), auth_hdr = tsk_null;
+ }
+ }
+ }
+
+ /* Update CSeq */
+ /* RFC 3261 - 13.2.2.4 2xx Responses
+ Generating ACK: The sequence number of the CSeq header field MUST be
+ the same as the INVITE being acknowledged, but the CSeq method MUST
+ be ACK. The ACK MUST contain the same credentials as the INVITE. If
+ the 2xx contains an offer (based on the rules above), the ACK MUST
+ carry an answer in its body.
+ ==> CSeq number will be added/updated by the caller of this function,
+ credentials were added above.
+ */
+ if(!TSIP_REQUEST_IS_ACK(request) && !TSIP_REQUEST_IS_CANCEL(request)) {
+ request->CSeq->seq = ++(TSIP_DIALOG(self)->cseq_value);
+ }
+
+ /* Route generation
+ * ==> http://betelco.blogspot.com/2008/11/proxy-and-service-route-discovery-in.html
+ * The dialog Routes have been copied above.
+
+ 3GPP TS 24.229 - 5.1.2A.1 UE-originating case
+
+ The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE
+ shall build a list of Route header field values made out of the following, in this order:
+ a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and
+ b) the P-CSCF port based on the security mechanism in use:
+
+ - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during
+ the registration procedure;
+ - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in
+ use as a security mechanism, the unprotected server port used during the registration procedure;
+ c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last
+ registration or re-registration of the public user identity with associated contact address.
+ */
+ if(!TSIP_REQUEST_IS_REGISTER(request)) {
+ // According to the above link ==> Initial/Re/De registration do not have routes.
+ if(copy_routes_start != -1) {
+ /* The dialog already have routes ==> copy them. */
+ if(self->state == tsip_early || self->state == tsip_established) {
+ int32_t index = -1;
+ tsk_list_foreach(item, self->record_routes) {
+ tsip_header_Record_Route_t *record_Route = ((tsip_header_Record_Route_t*)item->data);
+ const tsip_uri_t* uri = record_Route->uri;
+ tsip_header_Route_t *route = tsk_null;
+ if(++index < copy_routes_start || !uri) {
+ continue;
+ }
+
+ if((route = tsip_header_Route_create(uri))) {
+ // copy parameters: see http://code.google.com/p/imsdroid/issues/detail?id=52
+ if(!TSK_LIST_IS_EMPTY(TSIP_HEADER_PARAMS(record_Route))) {
+ if(!TSIP_HEADER_PARAMS(route)) {
+ TSIP_HEADER_PARAMS(route) = tsk_list_create();
+ }
+ tsk_list_pushback_list(TSIP_HEADER_PARAMS(route), TSIP_HEADER_PARAMS(record_Route));
+ }
+
+ tsip_message_add_header(request, TSIP_HEADER(route));
+ TSK_OBJECT_SAFE_FREE(route);
+ }
+ }
+ }
+ }
+ else {
+ /* No routes associated to this dialog. */
+ if(self->state == tsip_initial || self->state == tsip_early) {
+ /* GPP TS 24.229 section 5.1.2A [Generic procedures applicable to all methods excluding the REGISTER method]:
+ The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE
+ shall build a list of Route header field values made out of the following, in this order:
+ a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and
+ b) the P-CSCF port based on the security mechanism in use:
+ - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during
+ the registration procedure;
+ - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in
+ use as a security mechanism, the unprotected server port used during the registration procedure;
+ c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last
+ registration or re-registration of the public user identity with associated contact address.
+ */
#if _DEBUG && defined(SDS_HACK)/* FIXME: remove this */
- /* Ericsson SDS hack (INVITE with Proxy-CSCF as First route fail) */
+ /* Ericsson SDS hack (INVITE with Proxy-CSCF as First route fail) */
#elif 0
- tsip_uri_t *uri = tsip_stack_get_pcscf_uri(TSIP_DIALOG_GET_STACK(self), tsk_true);
- // Proxy-CSCF as first route
- if(uri){
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(uri));
- TSK_OBJECT_SAFE_FREE(uri);
- }
+ tsip_uri_t *uri = tsip_stack_get_pcscf_uri(TSIP_DIALOG_GET_STACK(self), tsk_true);
+ // Proxy-CSCF as first route
+ if(uri) {
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(uri));
+ TSK_OBJECT_SAFE_FREE(uri);
+ }
#endif
- // Service routes
- tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->service_routes){
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(item->data));
- }
- }
- }
- }
-
- /* Add headers associated to the session */
- tsip_dialog_add_session_headers(self, request);
-
- /* Add headers associated to the dialog's stack */
- TSIP_DIALOG_ADD_HEADERS(self->ss->stack->headers);
-
- /* Add common headers */
- tsip_dialog_add_common_headers(self, request);
-
- /* SigComp */
- if(self->ss->sigcomp_id){
- /* should be added in this field instead of 'Contact' or 'Via' headers
- * it's up to the transport layer to copy it to these headers */
- request->sigcomp_id = tsk_strdup(self->ss->sigcomp_id);
- }
-
- /* Remote Address: Used if "Server mode" otherwise Proxy-CSCF will be used */
- request->remote_addr = self->remote_addr;
- /* Connected FD */
- if(request->local_fd <= 0) {
- request->local_fd = self->connected_fd;
- }
-
- TSK_OBJECT_SAFE_FREE(request_uri);
- TSK_OBJECT_SAFE_FREE(from_uri);
- TSK_OBJECT_SAFE_FREE(to_uri);
-
- return request;
+ // Service routes
+ tsk_list_foreach(item, TSIP_DIALOG_GET_STACK(self)->service_routes) {
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_ROUTE_VA_ARGS(item->data));
+ }
+ }
+ }
+ }
+
+ /* Add headers associated to the session */
+ tsip_dialog_add_session_headers(self, request);
+
+ /* Add headers associated to the dialog's stack */
+ TSIP_DIALOG_ADD_HEADERS(self->ss->stack->headers);
+
+ /* Add common headers */
+ tsip_dialog_add_common_headers(self, request);
+
+ /* SigComp */
+ if(self->ss->sigcomp_id) {
+ /* should be added in this field instead of 'Contact' or 'Via' headers
+ * it's up to the transport layer to copy it to these headers */
+ request->sigcomp_id = tsk_strdup(self->ss->sigcomp_id);
+ }
+
+ /* Remote Address: Used if "Server mode" otherwise Proxy-CSCF will be used */
+ request->remote_addr = self->remote_addr;
+ /* Connected FD */
+ if(request->local_fd <= 0) {
+ request->local_fd = self->connected_fd;
+ }
+
+ TSK_OBJECT_SAFE_FREE(request_uri);
+ TSK_OBJECT_SAFE_FREE(from_uri);
+ TSK_OBJECT_SAFE_FREE(to_uri);
+
+ return request;
}
@@ -452,156 +450,155 @@ tsip_request_t *tsip_dialog_request_new(const tsip_dialog_t *self, const char* m
* @param self The parent dialog. All callback events will be notified to this dialog.
* @param request The request to send.
*
- * @return Zero if succeed and no-zero error code otherwise.
+ * @return Zero if succeed and no-zero error code otherwise.
**/
int tsip_dialog_request_send(const tsip_dialog_t *self, tsip_request_t* request)
{
- int ret = -1;
-
- if(self && TSIP_DIALOG_GET_STACK(self)){
- const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac;
- if(layer){
- /* Create new transaction. The new transaction will be added to the transaction layer.
- The transaction has all information to create the right transaction type (NICT or ICT).
- As this is an outgoing request ==> It shall be a client transaction (NICT or ICT).
- For server transactions creation see @ref tsip_dialog_response_send.
- */
- static const tsk_bool_t isCT = tsk_true;
- tsip_transac_t* transac;
- tsip_transac_dst_t* dst;
-
-
- if(TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))){
- const tsip_transport_t* transport = tsip_transport_layer_find_by_idx(TSIP_DIALOG_GET_STACK(self)->layer_transport, TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default);
- if(!transport){
- TSK_DEBUG_ERROR("Failed to find a valid default transport [%d]", TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default);
- }
- else{
- request->dst_net_type = transport->type;
- }
- }
- dst = tsip_transac_dst_dialog_create(TSIP_DIALOG(self));
- transac = tsip_transac_layer_new(
- layer,
- isCT,
- request,
- dst
- );
- TSK_OBJECT_SAFE_FREE(dst);
-
- /* Set the transaction's dialog. All events comming from the transaction (timeouts, errors ...) will be signaled to this dialog */
- if(transac){
- switch(transac->type)
- {
- case tsip_transac_type_ict:
- case tsip_transac_type_nict:
- {
- /* Start the newly create IC/NIC transaction */
- ret = tsip_transac_start(transac, request);
- break;
- }
- default: break;
- }
- TSK_OBJECT_SAFE_FREE(transac);
- }
- }
- }
- return ret;
+ int ret = -1;
+
+ if(self && TSIP_DIALOG_GET_STACK(self)) {
+ const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac;
+ if(layer) {
+ /* Create new transaction. The new transaction will be added to the transaction layer.
+ The transaction has all information to create the right transaction type (NICT or ICT).
+ As this is an outgoing request ==> It shall be a client transaction (NICT or ICT).
+ For server transactions creation see @ref tsip_dialog_response_send.
+ */
+ static const tsk_bool_t isCT = tsk_true;
+ tsip_transac_t* transac;
+ tsip_transac_dst_t* dst;
+
+
+ if(TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))) {
+ const tsip_transport_t* transport = tsip_transport_layer_find_by_idx(TSIP_DIALOG_GET_STACK(self)->layer_transport, TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default);
+ if(!transport) {
+ TSK_DEBUG_ERROR("Failed to find a valid default transport [%d]", TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default);
+ }
+ else {
+ request->dst_net_type = transport->type;
+ }
+ }
+ dst = tsip_transac_dst_dialog_create(TSIP_DIALOG(self));
+ transac = tsip_transac_layer_new(
+ layer,
+ isCT,
+ request,
+ dst
+ );
+ TSK_OBJECT_SAFE_FREE(dst);
+
+ /* Set the transaction's dialog. All events comming from the transaction (timeouts, errors ...) will be signaled to this dialog */
+ if(transac) {
+ switch(transac->type) {
+ case tsip_transac_type_ict:
+ case tsip_transac_type_nict: {
+ /* Start the newly create IC/NIC transaction */
+ ret = tsip_transac_start(transac, request);
+ break;
+ }
+ default:
+ break;
+ }
+ TSK_OBJECT_SAFE_FREE(transac);
+ }
+ }
+ }
+ return ret;
}
tsip_response_t *tsip_dialog_response_new(tsip_dialog_t *self, short status, const char* phrase, const tsip_request_t* request)
{
- /* Reponse is created as per RFC 3261 subclause 8.2.6 and (headers+tags) are copied
- * as per subclause 8.2.6.2.
- */
- tsip_response_t* response;
- if((response = tsip_response_new(status, phrase, request))){
- switch(request->line.request.request_type){
- case tsip_MESSAGE:
- case tsip_PUBLISH:
- break;
- default:
- /* Is there a To tag? */
- if(response->To && !response->To->tag){
- response->To->tag = tsk_strdup(self->tag_local);
- }
- /* Contact Header (for 101-299 reponses) */
- if(self->uri_local && TSIP_RESPONSE_CODE(response) >= 101 && TSIP_RESPONSE_CODE(response) <= 299){
- char* contact = tsk_null;
- tsip_header_Contacts_L_t *hdr_contacts;
-
- tsk_sprintf(&contact, "m: <%s:%s@%s:%d>\r\n", "sip", self->uri_local->user_name, "127.0.0.1", 5060);
- hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact));
- if(!TSK_LIST_IS_EMPTY(hdr_contacts)){
- response->Contact = tsk_object_ref(hdr_contacts->head->data);
- response->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact header) */
- }
- TSK_OBJECT_SAFE_FREE(hdr_contacts);
- TSK_FREE(contact);
- }
- break;
- }
-
- /* SigComp */
- if(self->ss->sigcomp_id){
- /* should be added in this field instead of 'Contact' or 'Via' headers
- * it's up to the transport layer to copy it to these headers */
- response->sigcomp_id = tsk_strdup(self->ss->sigcomp_id);
- }
- /* Connected FD */
- if(response->local_fd <= 0) {
- response->local_fd = self->connected_fd;
- }
- /* Remote Addr: used to send requests if "Server Mode" otherwise Proxy-CSCF address will be used */
- self->remote_addr = request->remote_addr;
- }
- return response;
+ /* Reponse is created as per RFC 3261 subclause 8.2.6 and (headers+tags) are copied
+ * as per subclause 8.2.6.2.
+ */
+ tsip_response_t* response;
+ if((response = tsip_response_new(status, phrase, request))) {
+ switch(request->line.request.request_type) {
+ case tsip_MESSAGE:
+ case tsip_PUBLISH:
+ break;
+ default:
+ /* Is there a To tag? */
+ if(response->To && !response->To->tag) {
+ response->To->tag = tsk_strdup(self->tag_local);
+ }
+ /* Contact Header (for 101-299 reponses) */
+ if(self->uri_local && TSIP_RESPONSE_CODE(response) >= 101 && TSIP_RESPONSE_CODE(response) <= 299) {
+ char* contact = tsk_null;
+ tsip_header_Contacts_L_t *hdr_contacts;
+
+ tsk_sprintf(&contact, "m: <%s:%s@%s:%d>\r\n", "sip", self->uri_local->user_name, "127.0.0.1", 5060);
+ hdr_contacts = tsip_header_Contact_parse(contact, tsk_strlen(contact));
+ if(!TSK_LIST_IS_EMPTY(hdr_contacts)) {
+ response->Contact = tsk_object_ref(hdr_contacts->head->data);
+ response->update = tsk_true; /* Now signal that the message should be updated by the transport layer (Contact header) */
+ }
+ TSK_OBJECT_SAFE_FREE(hdr_contacts);
+ TSK_FREE(contact);
+ }
+ break;
+ }
+
+ /* SigComp */
+ if(self->ss->sigcomp_id) {
+ /* should be added in this field instead of 'Contact' or 'Via' headers
+ * it's up to the transport layer to copy it to these headers */
+ response->sigcomp_id = tsk_strdup(self->ss->sigcomp_id);
+ }
+ /* Connected FD */
+ if(response->local_fd <= 0) {
+ response->local_fd = self->connected_fd;
+ }
+ /* Remote Addr: used to send requests if "Server Mode" otherwise Proxy-CSCF address will be used */
+ self->remote_addr = request->remote_addr;
+ }
+ return response;
}
int tsip_dialog_response_send(const tsip_dialog_t *self, tsip_response_t* response)
{
- int ret = -1;
-
- if(self && TSIP_DIALOG_GET_STACK(self)){
- const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac;
- if(layer){
- /* As this is a response ...then use the associate server transaction */
- tsip_transac_t *transac = tsip_transac_layer_find_server(layer, response);
- if(transac){
- ret = transac->callback(transac, tsip_transac_outgoing_msg, response);
- tsk_object_unref(transac);
- }
- else{
- TSK_DEBUG_ERROR("Failed to find associated server transaction.");
- // Send "408 Request Timeout" (should be done by the transaction layer)?
- }
- }
- }
- else{
- TSK_DEBUG_ERROR("Invalid parameter");
- }
- return ret;
+ int ret = -1;
+
+ if(self && TSIP_DIALOG_GET_STACK(self)) {
+ const tsip_transac_layer_t *layer = TSIP_DIALOG_GET_STACK(self)->layer_transac;
+ if(layer) {
+ /* As this is a response ...then use the associate server transaction */
+ tsip_transac_t *transac = tsip_transac_layer_find_server(layer, response);
+ if(transac) {
+ ret = transac->callback(transac, tsip_transac_outgoing_msg, response);
+ tsk_object_unref(transac);
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to find associated server transaction.");
+ // Send "408 Request Timeout" (should be done by the transaction layer)?
+ }
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ }
+ return ret;
}
int tsip_dialog_apply_action(tsip_message_t* message, const tsip_action_t* action)
{
- const tsk_list_item_t* item;
-
- if(!message || !action){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- /* SIP headers */
- tsk_list_foreach(item, action->headers){
- TSIP_MESSAGE_ADD_HEADER(message, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value));
- }
- /* Payload */
- if(action->payload){
- tsip_message_add_content(message, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload));
- }
-
- return 0;
+ const tsk_list_item_t* item;
+
+ if(!message || !action) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* SIP headers */
+ tsk_list_foreach(item, action->headers) {
+ TSIP_MESSAGE_ADD_HEADER(message, TSIP_HEADER_DUMMY_VA_ARGS(TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value));
+ }
+ /* Payload */
+ if(action->payload) {
+ tsip_message_add_content(message, tsk_null, TSK_BUFFER_DATA(action->payload), TSK_BUFFER_SIZE(action->payload));
+ }
+
+ return 0;
}
/**
@@ -612,72 +609,69 @@ int tsip_dialog_apply_action(tsip_message_t* message, const tsip_action_t* actio
* @param [in,out] self The calling dialog.
* @param [in,out] response The SIP/IMS response containing the new delay (expires, subscription-state ...).
*
- * @return Zero if succeed and no-zero error code otherwise.
+ * @return Zero if succeed and no-zero error code otherwise.
**/
int64_t tsip_dialog_get_newdelay(tsip_dialog_t *self, const tsip_message_t* message)
{
- int64_t expires = self->expires;
- int64_t newdelay = expires; /* default value */
- const tsip_header_t* hdr;
- tsk_size_t i;
-
- /*== NOTIFY with subscription-state header with expires parameter.
- */
- if(TSIP_REQUEST_IS_NOTIFY(message)){
- const tsip_header_Subscription_State_t *hdr_state;
- if((hdr_state = (const tsip_header_Subscription_State_t*)tsip_message_get_header(message, tsip_htype_Subscription_State))){
- if(hdr_state->expires >0){
- expires = TSK_TIME_S_2_MS(hdr_state->expires);
- goto compute;
- }
- }
- }
-
- /*== Expires header.
- */
- if((hdr = tsip_message_get_header(message, tsip_htype_Expires))){
- expires = TSK_TIME_S_2_MS(((const tsip_header_Expires_t*)hdr)->delta_seconds);
- goto compute;
- }
-
- /*== Contact header.
- */
- for(i=0; (hdr = tsip_message_get_headerAt(message, tsip_htype_Contact, i)); i++){
- const tsip_header_Contact_t* contact = (const tsip_header_Contact_t*)hdr;
- if(contact && contact->uri)
- {
- const char* transport = tsk_params_get_param_value(contact->uri->params, "transport");
- tsip_uri_t* contactUri = tsip_stack_get_contacturi(TSIP_DIALOG_GET_STACK(self), transport ? transport : "udp");
- if(contactUri)
- {
- if(tsk_strequals(contact->uri->user_name, contactUri->user_name)
- && tsk_strequals(contact->uri->host, contactUri->host)
- && contact->uri->port == contactUri->port)
- {
- if(contact->expires>=0){ /* No expires parameter ==> -1*/
- expires = TSK_TIME_S_2_MS(contact->expires);
-
- TSK_OBJECT_SAFE_FREE(contactUri);
- goto compute;
- }
- }
- TSK_OBJECT_SAFE_FREE(contactUri);
- }
- }
- }
-
- /*
- * 3GPP TS 24.229 -
- *
- * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial
- * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration
- * was for 1200 seconds or less.
- */
+ int64_t expires = self->expires;
+ int64_t newdelay = expires; /* default value */
+ const tsip_header_t* hdr;
+ tsk_size_t i;
+
+ /*== NOTIFY with subscription-state header with expires parameter.
+ */
+ if(TSIP_REQUEST_IS_NOTIFY(message)) {
+ const tsip_header_Subscription_State_t *hdr_state;
+ if((hdr_state = (const tsip_header_Subscription_State_t*)tsip_message_get_header(message, tsip_htype_Subscription_State))) {
+ if(hdr_state->expires >0) {
+ expires = TSK_TIME_S_2_MS(hdr_state->expires);
+ goto compute;
+ }
+ }
+ }
+
+ /*== Expires header.
+ */
+ if((hdr = tsip_message_get_header(message, tsip_htype_Expires))) {
+ expires = TSK_TIME_S_2_MS(((const tsip_header_Expires_t*)hdr)->delta_seconds);
+ goto compute;
+ }
+
+ /*== Contact header.
+ */
+ for(i=0; (hdr = tsip_message_get_headerAt(message, tsip_htype_Contact, i)); i++) {
+ const tsip_header_Contact_t* contact = (const tsip_header_Contact_t*)hdr;
+ if(contact && contact->uri) {
+ const char* transport = tsk_params_get_param_value(contact->uri->params, "transport");
+ tsip_uri_t* contactUri = tsip_stack_get_contacturi(TSIP_DIALOG_GET_STACK(self), transport ? transport : "udp");
+ if(contactUri) {
+ if(tsk_strequals(contact->uri->user_name, contactUri->user_name)
+ && tsk_strequals(contact->uri->host, contactUri->host)
+ && contact->uri->port == contactUri->port) {
+ if(contact->expires>=0) { /* No expires parameter ==> -1*/
+ expires = TSK_TIME_S_2_MS(contact->expires);
+
+ TSK_OBJECT_SAFE_FREE(contactUri);
+ goto compute;
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(contactUri);
+ }
+ }
+ }
+
+ /*
+ * 3GPP TS 24.229 -
+ *
+ * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial
+ * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration
+ * was for 1200 seconds or less.
+ */
compute:
- expires = TSK_TIME_MS_2_S(expires);
- newdelay = (expires > 1200) ? (expires - 600) : (expires/2);
+ expires = TSK_TIME_MS_2_S(expires);
+ newdelay = (expires > 1200) ? (expires - 600) : (expires/2);
- return TSK_TIME_S_2_MS(newdelay);
+ return TSK_TIME_S_2_MS(newdelay);
}
/**
@@ -690,488 +684,482 @@ compute:
* - ...
*
* @param [in,out] self The calling dialog.
- * @param [in,out] response The SIP/IMS response from which to get the new information.
+ * @param [in,out] response The SIP/IMS response from which to get the new information.
*
- * @return Zero if succeed and no-zero error code otherwise.
+ * @return Zero if succeed and no-zero error code otherwise.
**/
int tsip_dialog_update(tsip_dialog_t *self, const tsip_response_t* response)
{
- if(self && TSIP_MESSAGE_IS_RESPONSE(response) && response->To){
- short code = TSIP_RESPONSE_CODE(response);
- const char *tag = response->To->tag;
-
- /*
- * 1xx (!100) or 2xx
- */
- /*
- * 401 or 407 or 421 or 494
- */
- if(code == 401 || code == 407 || code == 421 || code == 494)
- {
- tsk_bool_t acceptNewVector;
-
- /* 3GPP IMS - Each authentication vector is used only once.
- * ==> Re-registration/De-registration ==> Allow 401/407 challenge.
- */
- acceptNewVector = (TSIP_RESPONSE_IS_TO_REGISTER(response) && self->state == tsip_established);
- return tsip_dialog_update_challenges(self, response, acceptNewVector);
- }
- else if(100 < code && code < 300)
- {
- tsip_dialog_state_t state = self->state;
-
- /* 1xx */
- if(code <= 199){
- if(tsk_strnullORempty(response->To->tag)){
- TSK_DEBUG_WARN("Invalid tag parameter");
- return 0;
- }
- state = tsip_early;
- }
- /* 2xx */
- else{
- state = tsip_established;
- }
-
- /* Remote target */
- {
- /* RFC 3261 12.2.1.2 Processing the Responses
- When a UAC receives a 2xx response to a target refresh request, it
- MUST replace the dialog's remote target URI with the URI from the
- Contact header field in that response, if present.
-
- FIXME: Because PRACK/UPDATE sent before the session is established MUST have
- the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected
- */
- if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && response->Contact && response->Contact->uri){
- TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
- self->uri_remote_target = tsip_uri_clone(response->Contact->uri, tsk_true, tsk_false);
- }
- }
-
- /* Route sets */
- {
- tsk_size_t index;
- const tsip_header_Record_Route_t *recordRoute;
- tsip_header_Record_Route_t *route;
-
- TSK_OBJECT_SAFE_FREE(self->record_routes);
-
- for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(response, tsip_htype_Record_Route, index)); index++){
- if(!self->record_routes){
- self->record_routes = tsk_list_create();
- }
- if((route = tsk_object_ref((void*)recordRoute))){
- tsk_list_push_front_data(self->record_routes, (void**)&route); /* Copy reversed. */
- }
- }
- }
-
-
- /* cseq + tags + ... */
- if(self->state == tsip_established && tsk_striequals(self->tag_remote, tag)){
- return 0;
- }
- else{
- if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && !TSIP_RESPONSE_IS_TO_PUBLISH(response)){ /* REGISTER and PUBLISH don't establish dialog */
- tsk_strupdate(&self->tag_remote, tag);
- }
+ if(self && TSIP_MESSAGE_IS_RESPONSE(response) && response->To) {
+ short code = TSIP_RESPONSE_CODE(response);
+ const char *tag = response->To->tag;
+
+ /*
+ * 1xx (!100) or 2xx
+ */
+ /*
+ * 401 or 407 or 421 or 494
+ */
+ if(code == 401 || code == 407 || code == 421 || code == 494) {
+ tsk_bool_t acceptNewVector;
+
+ /* 3GPP IMS - Each authentication vector is used only once.
+ * ==> Re-registration/De-registration ==> Allow 401/407 challenge.
+ */
+ acceptNewVector = (TSIP_RESPONSE_IS_TO_REGISTER(response) && self->state == tsip_established);
+ return tsip_dialog_update_challenges(self, response, acceptNewVector);
+ }
+ else if(100 < code && code < 300) {
+ tsip_dialog_state_t state = self->state;
+
+ /* 1xx */
+ if(code <= 199) {
+ if(tsk_strnullORempty(response->To->tag)) {
+ TSK_DEBUG_WARN("Invalid tag parameter");
+ return 0;
+ }
+ state = tsip_early;
+ }
+ /* 2xx */
+ else {
+ state = tsip_established;
+ }
+
+ /* Remote target */
+ {
+ /* RFC 3261 12.2.1.2 Processing the Responses
+ When a UAC receives a 2xx response to a target refresh request, it
+ MUST replace the dialog's remote target URI with the URI from the
+ Contact header field in that response, if present.
+
+ FIXME: Because PRACK/UPDATE sent before the session is established MUST have
+ the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected
+ */
+ if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && response->Contact && response->Contact->uri) {
+ TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
+ self->uri_remote_target = tsip_uri_clone(response->Contact->uri, tsk_true, tsk_false);
+ }
+ }
+
+ /* Route sets */
+ {
+ tsk_size_t index;
+ const tsip_header_Record_Route_t *recordRoute;
+ tsip_header_Record_Route_t *route;
+
+ TSK_OBJECT_SAFE_FREE(self->record_routes);
+
+ for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(response, tsip_htype_Record_Route, index)); index++) {
+ if(!self->record_routes) {
+ self->record_routes = tsk_list_create();
+ }
+ if((route = tsk_object_ref((void*)recordRoute))) {
+ tsk_list_push_front_data(self->record_routes, (void**)&route); /* Copy reversed. */
+ }
+ }
+ }
+
+
+ /* cseq + tags + ... */
+ if(self->state == tsip_established && tsk_striequals(self->tag_remote, tag)) {
+ return 0;
+ }
+ else {
+ if(!TSIP_RESPONSE_IS_TO_REGISTER(response) && !TSIP_RESPONSE_IS_TO_PUBLISH(response)) { /* REGISTER and PUBLISH don't establish dialog */
+ tsk_strupdate(&self->tag_remote, tag);
+ }
#if 0 // PRACK and BYE will have same CSeq value ==> Let CSeq value to be incremented by "tsip_dialog_request_new()"
- self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value;
+ self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value;
#endif
- }
+ }
- self->state = state;
- return 0;
- }
- }
- return 0;
+ self->state = state;
+ return 0;
+ }
+ }
+ return 0;
}
int tsip_dialog_update_2(tsip_dialog_t *self, const tsip_request_t* invite)
{
- if(!self || !invite){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- /* Remote target */
- if(invite->Contact && invite->Contact->uri){
- TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
- self->uri_remote_target = tsip_uri_clone(invite->Contact->uri, tsk_true, tsk_false);
- }
-
- /* cseq + tags + remote-uri */
- tsk_strupdate(&self->tag_remote, invite->From?invite->From->tag:"doubango");
- /* self->cseq_value = invite->CSeq ? invite->CSeq->seq : self->cseq_value; */
- if(invite->From && invite->From->uri){
- TSK_OBJECT_SAFE_FREE(self->uri_remote);
- self->uri_remote = tsk_object_ref(invite->From->uri);
- }
-
- /* Route sets */
- {
- tsk_size_t index;
- const tsip_header_Record_Route_t *recordRoute;
- tsip_header_Record_Route_t* route;
-
- TSK_OBJECT_SAFE_FREE(self->record_routes);
-
- for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(invite, tsip_htype_Record_Route, index)); index++){
- if(!self->record_routes){
- self->record_routes = tsk_list_create();
- }
- if((route = tsk_object_ref((void*)recordRoute))){
- tsk_list_push_back_data(self->record_routes, (void**)&route); /* Copy non-reversed. */
- }
- }
- }
-
- self->state = tsip_established;
-
- return 0;
+ if(!self || !invite) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* Remote target */
+ if(invite->Contact && invite->Contact->uri) {
+ TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
+ self->uri_remote_target = tsip_uri_clone(invite->Contact->uri, tsk_true, tsk_false);
+ }
+
+ /* cseq + tags + remote-uri */
+ tsk_strupdate(&self->tag_remote, invite->From?invite->From->tag:"doubango");
+ /* self->cseq_value = invite->CSeq ? invite->CSeq->seq : self->cseq_value; */
+ if(invite->From && invite->From->uri) {
+ TSK_OBJECT_SAFE_FREE(self->uri_remote);
+ self->uri_remote = tsk_object_ref(invite->From->uri);
+ }
+
+ /* Route sets */
+ {
+ tsk_size_t index;
+ const tsip_header_Record_Route_t *recordRoute;
+ tsip_header_Record_Route_t* route;
+
+ TSK_OBJECT_SAFE_FREE(self->record_routes);
+
+ for(index = 0; (recordRoute = (const tsip_header_Record_Route_t *)tsip_message_get_headerAt(invite, tsip_htype_Record_Route, index)); index++) {
+ if(!self->record_routes) {
+ self->record_routes = tsk_list_create();
+ }
+ if((route = tsk_object_ref((void*)recordRoute))) {
+ tsk_list_push_back_data(self->record_routes, (void**)&route); /* Copy non-reversed. */
+ }
+ }
+ }
+
+ self->state = tsip_established;
+
+ return 0;
}
int tsip_dialog_getCKIK(tsip_dialog_t *self, AKA_CK_T *ck, AKA_IK_T *ik)
{
- tsk_list_item_t *item;
- tsip_challenge_t *challenge;
-
- if(!self){
- return -1;
- }
-
- tsk_list_foreach(item, self->challenges)
- {
- if((challenge = item->data)){
- memcpy(*ck, challenge->ck, AKA_CK_SIZE);
- memcpy(*ik, challenge->ik, AKA_IK_SIZE);
- return 0;
- }
- }
- TSK_DEBUG_ERROR("No challenge found. Fail to set IK and CK.");
- return -2;
+ tsk_list_item_t *item;
+ tsip_challenge_t *challenge;
+
+ if(!self) {
+ return -1;
+ }
+
+ tsk_list_foreach(item, self->challenges) {
+ if((challenge = item->data)) {
+ memcpy(*ck, challenge->ck, AKA_CK_SIZE);
+ memcpy(*ik, challenge->ik, AKA_IK_SIZE);
+ return 0;
+ }
+ }
+ TSK_DEBUG_ERROR("No challenge found. Fail to set IK and CK.");
+ return -2;
}
int tsip_dialog_update_challenges(tsip_dialog_t *self, const tsip_response_t* response, int acceptNewVector)
{
- int ret = -1;
- tsk_size_t i;
-
- tsk_list_item_t *item;
-
- tsip_challenge_t *challenge;
-
- const tsip_header_WWW_Authenticate_t *WWW_Authenticate;
- const tsip_header_Proxy_Authenticate_t *Proxy_Authenticate;
-
- /* RFC 2617 - HTTP Digest Session
-
- * (A) The client response to a WWW-Authenticate challenge for a protection
- space starts an authentication session with that protection space.
- The authentication session lasts until the client receives another
- WWW-Authenticate challenge from any server in the protection space.
-
- (B) The server may return a 401 response with a new nonce value, causing the client
- to retry the request; by specifying stale=TRUE with this response,
- the server tells the client to retry with the new nonce, but without
- prompting for a new username and password.
- */
- /* RFC 2617 - 1.2 Access Authentication Framework
- The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge.
- */
-
- /* FIXME: As we perform the same task ==> Use only one loop.
- */
-
- for(i =0; (WWW_Authenticate = (const tsip_header_WWW_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_WWW_Authenticate, i)); i++){
- tsk_bool_t isnew = tsk_true;
-
- tsk_list_foreach(item, self->challenges){
- challenge = item->data;
- if(challenge->isproxy) continue;
-
- if(tsk_striequals(challenge->realm, WWW_Authenticate->realm) && (WWW_Authenticate->stale || acceptNewVector)){
- /*== (B) ==*/
- if((ret = tsip_challenge_update(challenge,
- WWW_Authenticate->scheme,
- WWW_Authenticate->realm,
- WWW_Authenticate->nonce,
- WWW_Authenticate->opaque,
- WWW_Authenticate->algorithm,
- WWW_Authenticate->qop)))
- {
- return ret;
- }
- else{
- isnew = tsk_false;
- continue;
- }
- }
- else{
- TSK_DEBUG_ERROR("Failed to handle new challenge");
- return -1;
- }
- }
-
- if(isnew){
- if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self),
- tsk_false,
- WWW_Authenticate->scheme,
- WWW_Authenticate->realm,
- WWW_Authenticate->nonce,
- WWW_Authenticate->opaque,
- WWW_Authenticate->algorithm,
- WWW_Authenticate->qop)))
- {
- if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi){
- tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1);
- }
- tsk_list_push_back_data(self->challenges, (void**)&challenge);
- }
- else{
- TSK_DEBUG_ERROR("Failed to handle new challenge");
- return -1;
- }
- }
- }
-
- for(i=0; (Proxy_Authenticate = (const tsip_header_Proxy_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_Proxy_Authenticate, i)); i++){
- tsk_bool_t isnew = tsk_true;
-
- tsk_list_foreach(item, self->challenges){
- challenge = item->data;
- if(!challenge->isproxy){
- continue;
- }
-
- if(tsk_striequals(challenge->realm, Proxy_Authenticate->realm) && (Proxy_Authenticate->stale || acceptNewVector)){
- /*== (B) ==*/
- if((ret = tsip_challenge_update(challenge,
- Proxy_Authenticate->scheme,
- Proxy_Authenticate->realm,
- Proxy_Authenticate->nonce,
- Proxy_Authenticate->opaque,
- Proxy_Authenticate->algorithm,
- Proxy_Authenticate->qop)))
- {
- return ret;
- }
- else{
- isnew = tsk_false;
- continue;
- }
- }
- else{
- TSK_DEBUG_ERROR("Failed to handle new challenge");
- return -1;
- }
- }
-
- if(isnew){
- if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self),
- tsk_true,
- Proxy_Authenticate->scheme,
- Proxy_Authenticate->realm,
- Proxy_Authenticate->nonce,
- Proxy_Authenticate->opaque,
- Proxy_Authenticate->algorithm,
- Proxy_Authenticate->qop)))
- {
- if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi){
- tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1);
- }
- tsk_list_push_back_data(self->challenges, (void**)&challenge);
- }
- else{
- TSK_DEBUG_ERROR("Failed to handle new challenge");
- return -1;
- }
- }
- }
- return 0;
+ int ret = -1;
+ tsk_size_t i;
+
+ tsk_list_item_t *item;
+
+ tsip_challenge_t *challenge;
+
+ const tsip_header_WWW_Authenticate_t *WWW_Authenticate;
+ const tsip_header_Proxy_Authenticate_t *Proxy_Authenticate;
+
+ /* RFC 2617 - HTTP Digest Session
+
+ * (A) The client response to a WWW-Authenticate challenge for a protection
+ space starts an authentication session with that protection space.
+ The authentication session lasts until the client receives another
+ WWW-Authenticate challenge from any server in the protection space.
+
+ (B) The server may return a 401 response with a new nonce value, causing the client
+ to retry the request; by specifying stale=TRUE with this response,
+ the server tells the client to retry with the new nonce, but without
+ prompting for a new username and password.
+ */
+ /* RFC 2617 - 1.2 Access Authentication Framework
+ The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge.
+ */
+
+ /* FIXME: As we perform the same task ==> Use only one loop.
+ */
+
+ for(i =0; (WWW_Authenticate = (const tsip_header_WWW_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_WWW_Authenticate, i)); i++) {
+ tsk_bool_t isnew = tsk_true;
+
+ tsk_list_foreach(item, self->challenges) {
+ challenge = item->data;
+ if(challenge->isproxy) {
+ continue;
+ }
+
+ if(tsk_striequals(challenge->realm, WWW_Authenticate->realm) && (WWW_Authenticate->stale || acceptNewVector)) {
+ /*== (B) ==*/
+ if((ret = tsip_challenge_update(challenge,
+ WWW_Authenticate->scheme,
+ WWW_Authenticate->realm,
+ WWW_Authenticate->nonce,
+ WWW_Authenticate->opaque,
+ WWW_Authenticate->algorithm,
+ WWW_Authenticate->qop))) {
+ return ret;
+ }
+ else {
+ isnew = tsk_false;
+ continue;
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to handle new challenge");
+ return -1;
+ }
+ }
+
+ if(isnew) {
+ if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self),
+ tsk_false,
+ WWW_Authenticate->scheme,
+ WWW_Authenticate->realm,
+ WWW_Authenticate->nonce,
+ WWW_Authenticate->opaque,
+ WWW_Authenticate->algorithm,
+ WWW_Authenticate->qop))) {
+ if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi) {
+ tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1);
+ }
+ tsk_list_push_back_data(self->challenges, (void**)&challenge);
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to handle new challenge");
+ return -1;
+ }
+ }
+ }
+
+ for(i=0; (Proxy_Authenticate = (const tsip_header_Proxy_Authenticate_t*)tsip_message_get_headerAt(response, tsip_htype_Proxy_Authenticate, i)); i++) {
+ tsk_bool_t isnew = tsk_true;
+
+ tsk_list_foreach(item, self->challenges) {
+ challenge = item->data;
+ if(!challenge->isproxy) {
+ continue;
+ }
+
+ if(tsk_striequals(challenge->realm, Proxy_Authenticate->realm) && (Proxy_Authenticate->stale || acceptNewVector)) {
+ /*== (B) ==*/
+ if((ret = tsip_challenge_update(challenge,
+ Proxy_Authenticate->scheme,
+ Proxy_Authenticate->realm,
+ Proxy_Authenticate->nonce,
+ Proxy_Authenticate->opaque,
+ Proxy_Authenticate->algorithm,
+ Proxy_Authenticate->qop))) {
+ return ret;
+ }
+ else {
+ isnew = tsk_false;
+ continue;
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to handle new challenge");
+ return -1;
+ }
+ }
+
+ if(isnew) {
+ if((challenge = tsip_challenge_create(TSIP_DIALOG_GET_STACK(self),
+ tsk_true,
+ Proxy_Authenticate->scheme,
+ Proxy_Authenticate->realm,
+ Proxy_Authenticate->nonce,
+ Proxy_Authenticate->opaque,
+ Proxy_Authenticate->algorithm,
+ Proxy_Authenticate->qop))) {
+ if(TSIP_DIALOG_GET_SS(self)->auth_ha1 && TSIP_DIALOG_GET_SS(self)->auth_impi) {
+ tsip_challenge_set_cred(challenge, TSIP_DIALOG_GET_SS(self)->auth_impi, TSIP_DIALOG_GET_SS(self)->auth_ha1);
+ }
+ tsk_list_push_back_data(self->challenges, (void**)&challenge);
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to handle new challenge");
+ return -1;
+ }
+ }
+ }
+ return 0;
}
int tsip_dialog_add_session_headers(const tsip_dialog_t *self, tsip_request_t* request)
{
- if(!self || !request){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if(!self || !request) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- TSIP_DIALOG_ADD_HEADERS(self->ss->headers);
- return 0;
+ TSIP_DIALOG_ADD_HEADERS(self->ss->headers);
+ return 0;
}
int tsip_dialog_add_common_headers(const tsip_dialog_t *self, tsip_request_t* request)
{
- tsk_bool_t earlyIMS = tsk_false;
- const tsip_uri_t* preferred_identity = tsk_null;
- const char* netinfo = tsk_null;
-
- if(!self || !request){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- earlyIMS = TSIP_DIALOG_GET_STACK(self)->security.earlyIMS;
- preferred_identity = TSIP_DIALOG_GET_STACK(self)->identity.preferred;
-
- //
- // P-Preferred-Identity
- //
- if(preferred_identity && TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))){
- /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE
- The UE shall use the temporary public user identity (IMSI-derived IMPU, cf. section 6.1.2) only in registration
- messages (i.e. initial registration, re-registration or de-registration), but not in any other type of SIP requests.
- */
- switch(request->line.request.request_type){
- case tsip_BYE:
- case tsip_INVITE:
- case tsip_OPTIONS:
- case tsip_SUBSCRIBE:
- case tsip_NOTIFY:
- case tsip_REFER:
- case tsip_MESSAGE:
- case tsip_PUBLISH:
- case tsip_REGISTER:
- {
- if(!earlyIMS || (earlyIMS && TSIP_REQUEST_IS_REGISTER(request))){
- TSIP_MESSAGE_ADD_HEADER(request,
- TSIP_HEADER_P_PREFERRED_IDENTITY_VA_ARGS(preferred_identity)
- );
- }
- break;
- }
- default:break;
- }
- }
-
- //
- // P-Access-Network-Info
- //
- if(netinfo)
- {
- switch(request->line.request.request_type){
- case tsip_BYE:
- case tsip_INVITE:
- case tsip_OPTIONS:
- case tsip_REGISTER:
- case tsip_SUBSCRIBE:
- case tsip_NOTIFY:
- case tsip_PRACK:
- case tsip_INFO:
- case tsip_UPDATE:
- case tsip_REFER:
- case tsip_MESSAGE:
- case tsip_PUBLISH:
- {
- TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_P_ACCESS_NETWORK_INFO_VA_ARGS(netinfo));
- break;
- }
- default: break;
- }
- }
-
- return 0;
+ tsk_bool_t earlyIMS = tsk_false;
+ const tsip_uri_t* preferred_identity = tsk_null;
+ const char* netinfo = tsk_null;
+
+ if(!self || !request) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ earlyIMS = TSIP_DIALOG_GET_STACK(self)->security.earlyIMS;
+ preferred_identity = TSIP_DIALOG_GET_STACK(self)->identity.preferred;
+
+ //
+ // P-Preferred-Identity
+ //
+ if(preferred_identity && TSIP_STACK_MODE_IS_CLIENT(TSIP_DIALOG_GET_STACK(self))) {
+ /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE
+ The UE shall use the temporary public user identity (IMSI-derived IMPU, cf. section 6.1.2) only in registration
+ messages (i.e. initial registration, re-registration or de-registration), but not in any other type of SIP requests.
+ */
+ switch(request->line.request.request_type) {
+ case tsip_BYE:
+ case tsip_INVITE:
+ case tsip_OPTIONS:
+ case tsip_SUBSCRIBE:
+ case tsip_NOTIFY:
+ case tsip_REFER:
+ case tsip_MESSAGE:
+ case tsip_PUBLISH:
+ case tsip_REGISTER: {
+ if(!earlyIMS || (earlyIMS && TSIP_REQUEST_IS_REGISTER(request))) {
+ TSIP_MESSAGE_ADD_HEADER(request,
+ TSIP_HEADER_P_PREFERRED_IDENTITY_VA_ARGS(preferred_identity)
+ );
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ //
+ // P-Access-Network-Info
+ //
+ if(netinfo) {
+ switch(request->line.request.request_type) {
+ case tsip_BYE:
+ case tsip_INVITE:
+ case tsip_OPTIONS:
+ case tsip_REGISTER:
+ case tsip_SUBSCRIBE:
+ case tsip_NOTIFY:
+ case tsip_PRACK:
+ case tsip_INFO:
+ case tsip_UPDATE:
+ case tsip_REFER:
+ case tsip_MESSAGE:
+ case tsip_PUBLISH: {
+ TSIP_MESSAGE_ADD_HEADER(request, TSIP_HEADER_P_ACCESS_NETWORK_INFO_VA_ARGS(netinfo));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return 0;
}
int tsip_dialog_init(tsip_dialog_t *self, tsip_dialog_type_t type, const char* call_id, tsip_ssession_t* ss, tsk_fsm_state_id curr, tsk_fsm_state_id term)
{
- static tsip_dialog_id_t unique_id = 0;
- if(self){
- if(self->initialized){
- TSK_DEBUG_WARN("Dialog already initialized.");
- return -2;
- }
-
- self->state = tsip_initial;
- self->type = type;
- self->id = ++unique_id;
- self->connected_fd = TNET_INVALID_FD;
- if(!self->record_routes){
- self->record_routes = tsk_list_create();
- }
- if(!self->challenges){
- self->challenges = tsk_list_create();
- }
-
- /* Sets some defalt values */
- self->expires = TSIP_SSESSION_EXPIRES_DEFAULT;
-
- if(call_id){
- /* "server-side" session */
- tsk_strupdate(&self->callid, call_id);
- }
- else{
- tsk_uuidstring_t uuid; /* Call-id is a random UUID */
- tsip_header_Call_ID_random(&uuid);
- tsk_strupdate(&self->callid, uuid);
- }
-
- /* ref SIP session */
- self->ss = tsk_object_ref(ss);
-
- /* Local tag */{
- tsk_istr_t tag;
- tsk_strrandom(&tag);
- tsk_strupdate(&self->tag_local, tag);
- }
-
- /* CSeq */
- self->cseq_value = (rand() + 1);
-
- /* FSM */
- self->fsm = tsk_fsm_create(curr, term);
-
- /*=== SIP Session ===*/
- if(self->ss != TSIP_SSESSION_INVALID_HANDLE){
-
- /* Expires */
- self->expires = ss->expires;
-
- /* From */
- self->uri_local = tsk_object_ref(call_id/* "server-side" */ ? ss->to : ss->from);
-
- /* To */
- if(ss->to){
- self->uri_remote = tsk_object_ref(ss->to);
- self->uri_remote_target = tsk_object_ref(ss->to); /* Request-URI. */
- }
- else{
- self->uri_remote = tsk_object_ref(ss->from);
- self->uri_remote_target = tsk_object_ref((void*)TSIP_DIALOG_GET_STACK(self)->network.realm);
- }
- }
- else{
- TSK_DEBUG_ERROR("Invalid SIP Session id.");
- }
-
- tsk_safeobj_init(self);
-
- self->initialized = tsk_true;
- return 0;
- }
- return -1;
+ static tsip_dialog_id_t unique_id = 0;
+ if(self) {
+ if(self->initialized) {
+ TSK_DEBUG_WARN("Dialog already initialized.");
+ return -2;
+ }
+
+ self->state = tsip_initial;
+ self->type = type;
+ self->id = ++unique_id;
+ self->connected_fd = TNET_INVALID_FD;
+ if(!self->record_routes) {
+ self->record_routes = tsk_list_create();
+ }
+ if(!self->challenges) {
+ self->challenges = tsk_list_create();
+ }
+
+ /* Sets some defalt values */
+ self->expires = TSIP_SSESSION_EXPIRES_DEFAULT;
+
+ if(call_id) {
+ /* "server-side" session */
+ tsk_strupdate(&self->callid, call_id);
+ }
+ else {
+ tsk_uuidstring_t uuid; /* Call-id is a random UUID */
+ tsip_header_Call_ID_random(&uuid);
+ tsk_strupdate(&self->callid, uuid);
+ }
+
+ /* ref SIP session */
+ self->ss = tsk_object_ref(ss);
+
+ /* Local tag */{
+ tsk_istr_t tag;
+ tsk_strrandom(&tag);
+ tsk_strupdate(&self->tag_local, tag);
+ }
+
+ /* CSeq */
+ self->cseq_value = (rand() + 1);
+
+ /* FSM */
+ self->fsm = tsk_fsm_create(curr, term);
+
+ /*=== SIP Session ===*/
+ if(self->ss != TSIP_SSESSION_INVALID_HANDLE) {
+
+ /* Expires */
+ self->expires = ss->expires;
+
+ /* From */
+ self->uri_local = tsk_object_ref(call_id/* "server-side" */ ? ss->to : ss->from);
+
+ /* To */
+ if(ss->to) {
+ self->uri_remote = tsk_object_ref(ss->to);
+ self->uri_remote_target = tsk_object_ref(ss->to); /* Request-URI. */
+ }
+ else {
+ self->uri_remote = tsk_object_ref(ss->from);
+ self->uri_remote_target = tsk_object_ref((void*)TSIP_DIALOG_GET_STACK(self)->network.realm);
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Invalid SIP Session id.");
+ }
+
+ tsk_safeobj_init(self);
+
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -1;
}
int tsip_dialog_fsm_act(tsip_dialog_t* self, tsk_fsm_action_id action_id, const tsip_message_t* message, const tsip_action_handle_t* action)
{
- int ret;
- tsip_dialog_t* copy;
- if(!self || !self->fsm){
- TSK_DEBUG_ERROR("Invalid parameter.");
- return -1;
- }
-
- tsk_safeobj_lock(self);
- copy = tsk_object_ref(self); /* keep a copy because tsk_fsm_act() could destroy the dialog */
- ret = tsip_dialog_set_curr_action(copy, action);
- ret = tsk_fsm_act(copy->fsm, action_id, copy, message, copy, message, action);
- tsk_safeobj_unlock(copy);
- tsk_object_unref(copy);
-
- return ret;
+ int ret;
+ tsip_dialog_t* copy;
+ if(!self || !self->fsm) {
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+ copy = tsk_object_ref(self); /* keep a copy because tsk_fsm_act() could destroy the dialog */
+ ret = tsip_dialog_set_curr_action(copy, action);
+ ret = tsk_fsm_act(copy->fsm, action_id, copy, message, copy, message, action);
+ tsk_safeobj_unlock(copy);
+ tsk_object_unref(copy);
+
+ return ret;
}
/*
@@ -1179,176 +1167,175 @@ This function is used to know if we need to keep the same action handle after re
*/
tsk_bool_t tsip_dialog_keep_action(const tsip_dialog_t* self, const tsip_response_t *response)
{
- if(self && response){
- const short code = TSIP_RESPONSE_CODE(response);
- return
- TSIP_RESPONSE_IS_1XX(response) ||
- (code == 401 || code == 407 || code == 421 || code == 494) ||
- (code == 422 || code == 423);
- }
- return tsk_false;
+ if(self && response) {
+ const short code = TSIP_RESPONSE_CODE(response);
+ return
+ TSIP_RESPONSE_IS_1XX(response) ||
+ (code == 401 || code == 407 || code == 421 || code == 494) ||
+ (code == 422 || code == 423);
+ }
+ return tsk_false;
}
int tsip_dialog_set_connected_fd(tsip_dialog_t* self, tnet_fd_t fd)
{
- if(!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- self->connected_fd = fd;
- return 0;
+ if(!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->connected_fd = fd;
+ return 0;
}
int tsip_dialog_set_curr_action(tsip_dialog_t* self, const tsip_action_t* action)
{
- tsip_action_t* new_action;
- if(!self){
- TSK_DEBUG_ERROR("Invalid parameter.");
- return -1;
- }
-
- new_action = tsk_object_ref((void*)action);
- TSK_OBJECT_SAFE_FREE(self->curr_action);
- self->curr_action = new_action;
- return 0;
+ tsip_action_t* new_action;
+ if(!self) {
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ new_action = tsk_object_ref((void*)action);
+ TSK_OBJECT_SAFE_FREE(self->curr_action);
+ self->curr_action = new_action;
+ return 0;
}
int tsip_dialog_set_lasterror_2(tsip_dialog_t* self, const char* phrase, short code, const tsip_message_t *message)
{
- if(!self || tsk_strnullORempty(phrase)){
- TSK_DEBUG_ERROR("Invalid parameter.");
- return -1;
- }
-
- tsk_strupdate(&self->last_error.phrase, phrase);
- self->last_error.code = code;
- TSK_OBJECT_SAFE_FREE(self->last_error.message);
- if(message){
- self->last_error.message = (tsip_message_t*)tsk_object_ref((void*)message);
- }
- return 0;
+ if(!self || tsk_strnullORempty(phrase)) {
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ tsk_strupdate(&self->last_error.phrase, phrase);
+ self->last_error.code = code;
+ TSK_OBJECT_SAFE_FREE(self->last_error.message);
+ if(message) {
+ self->last_error.message = (tsip_message_t*)tsk_object_ref((void*)message);
+ }
+ return 0;
}
int tsip_dialog_set_lasterror(tsip_dialog_t* self, const char* phrase, short code)
{
- return tsip_dialog_set_lasterror_2(self, phrase, code, tsk_null);
+ return tsip_dialog_set_lasterror_2(self, phrase, code, tsk_null);
}
int tsip_dialog_get_lasterror(const tsip_dialog_t* self, short *code, const char** phrase, const tsip_message_t **message)
{
- if(!self){
- TSK_DEBUG_ERROR("Invalid parameter.");
- return -1;
- }
-
- if(code){
- *code = self->last_error.code;
- }
- if(phrase){
- *phrase = self->last_error.phrase;
- }
-
- if(message){
- *message = self->last_error.message;
- }
-
- return 0;
+ if(!self) {
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ if(code) {
+ *code = self->last_error.code;
+ }
+ if(phrase) {
+ *phrase = self->last_error.phrase;
+ }
+
+ if(message) {
+ *message = self->last_error.message;
+ }
+
+ return 0;
}
int tsip_dialog_hangup(tsip_dialog_t *self, const tsip_action_t* action)
{
- if(self){
- // CANCEL should only be sent for INVITE dialog
- if(self->type != tsip_dialog_INVITE || self->state == tsip_established){
- return tsip_dialog_fsm_act(self, tsip_atype_hangup, tsk_null, action);
- }
- else{
- return tsip_dialog_fsm_act(self, tsip_atype_cancel, tsk_null, action);
- }
- }
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
+ if(self) {
+ // CANCEL should only be sent for INVITE dialog
+ if(self->type != tsip_dialog_INVITE || self->state == tsip_established) {
+ return tsip_dialog_fsm_act(self, tsip_atype_hangup, tsk_null, action);
+ }
+ else {
+ return tsip_dialog_fsm_act(self, tsip_atype_cancel, tsk_null, action);
+ }
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
}
int tsip_dialog_shutdown(tsip_dialog_t *self, const tsip_action_t* action)
{
- if(self){
- return tsip_dialog_fsm_act(self, tsip_atype_shutdown, tsk_null, action);
- }
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
+ if(self) {
+ return tsip_dialog_fsm_act(self, tsip_atype_shutdown, tsk_null, action);
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
}
int tsip_dialog_signal_transport_error(tsip_dialog_t *self)
{
- if(self){
- return tsip_dialog_fsm_act(self, tsip_atype_transport_error, tsk_null, tsk_null);
- }
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
+ if(self) {
+ return tsip_dialog_fsm_act(self, tsip_atype_transport_error, tsk_null, tsk_null);
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
}
int tsip_dialog_remove(const tsip_dialog_t* self)
{
- return tsip_dialog_layer_remove(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG(self));
+ return tsip_dialog_layer_remove(TSIP_DIALOG_GET_STACK(self)->layer_dialog, TSIP_DIALOG(self));
}
int tsip_dialog_cmp(const tsip_dialog_t *d1, const tsip_dialog_t *d2)
{
- if(d1 && d2){
- if(
- tsk_strequals(d1->callid, d2->callid)
- && (tsk_strequals(d1->tag_local, d2->tag_local))
- && (tsk_strequals(d1->tag_remote, d2->tag_remote))
- )
- {
- return 0;
- }
- }
- return -1;
+ if(d1 && d2) {
+ if(
+ tsk_strequals(d1->callid, d2->callid)
+ && (tsk_strequals(d1->tag_local, d2->tag_local))
+ && (tsk_strequals(d1->tag_remote, d2->tag_remote))
+ ) {
+ return 0;
+ }
+ }
+ return -1;
}
int tsip_dialog_deinit(tsip_dialog_t *self)
{
- if(self){
- if(!self->initialized){
- TSK_DEBUG_WARN("Dialog not initialized.");
- return -2;
- }
-
- /* Cancel all transactions associated to this dialog (do it here before the dialog becomes unsafe) */
- tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, self);
-
- /* Remove the dialog from the Stream peers */
- tsip_dialog_layer_remove_callid_from_stream_peers(TSIP_DIALOG_GET_STACK(self)->layer_dialog, self->callid);
-
- TSK_OBJECT_SAFE_FREE(self->ss);
- TSK_OBJECT_SAFE_FREE(self->curr_action);
-
- TSK_OBJECT_SAFE_FREE(self->uri_local);
- TSK_FREE(self->tag_local);
- TSK_OBJECT_SAFE_FREE(self->uri_remote);
- TSK_FREE(self->tag_remote);
-
- TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
-
- TSK_FREE(self->cseq_method);
- TSK_FREE(self->callid);
-
- TSK_FREE(self->last_error.phrase);
- TSK_OBJECT_SAFE_FREE(self->last_error.message);
-
- TSK_OBJECT_SAFE_FREE(self->record_routes);
- TSK_OBJECT_SAFE_FREE(self->challenges);
-
- TSK_OBJECT_SAFE_FREE(self->fsm);
-
- tsk_safeobj_deinit(self);
-
- self->initialized = 0;
-
- return 0;
- }
- return -1;
+ if(self) {
+ if(!self->initialized) {
+ TSK_DEBUG_WARN("Dialog not initialized.");
+ return -2;
+ }
+
+ /* Cancel all transactions associated to this dialog (do it here before the dialog becomes unsafe) */
+ tsip_transac_layer_cancel_by_dialog(TSIP_DIALOG_GET_STACK(self)->layer_transac, self);
+
+ /* Remove the dialog from the Stream peers */
+ tsip_dialog_layer_remove_callid_from_stream_peers(TSIP_DIALOG_GET_STACK(self)->layer_dialog, self->callid);
+
+ TSK_OBJECT_SAFE_FREE(self->ss);
+ TSK_OBJECT_SAFE_FREE(self->curr_action);
+
+ TSK_OBJECT_SAFE_FREE(self->uri_local);
+ TSK_FREE(self->tag_local);
+ TSK_OBJECT_SAFE_FREE(self->uri_remote);
+ TSK_FREE(self->tag_remote);
+
+ TSK_OBJECT_SAFE_FREE(self->uri_remote_target);
+
+ TSK_FREE(self->cseq_method);
+ TSK_FREE(self->callid);
+
+ TSK_FREE(self->last_error.phrase);
+ TSK_OBJECT_SAFE_FREE(self->last_error.message);
+
+ TSK_OBJECT_SAFE_FREE(self->record_routes);
+ TSK_OBJECT_SAFE_FREE(self->challenges);
+
+ TSK_OBJECT_SAFE_FREE(self->fsm);
+
+ tsk_safeobj_deinit(self);
+
+ self->initialized = 0;
+
+ return 0;
+ }
+ return -1;
}
OpenPOWER on IntegriCloud