diff options
Diffstat (limited to 'tinySIP/src/tsip_message.c')
-rwxr-xr-x | tinySIP/src/tsip_message.c | 994 |
1 files changed, 519 insertions, 475 deletions
diff --git a/tinySIP/src/tsip_message.c b/tinySIP/src/tsip_message.c index 5ac2545..89f2f41 100755 --- a/tinySIP/src/tsip_message.c +++ b/tinySIP/src/tsip_message.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org> -* +* * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. -* +* * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License * along with DOUBANGO. * @@ -49,43 +49,43 @@ /*== Predicate function to find tsk_string_t object by val*/ static int __pred_find_string_by_value(const tsk_list_item_t *item, const void *stringVal) { - if(item && item->data){ - tsk_string_t *string = item->data; - return tsk_stricmp(string->value, stringVal); - } - return -1; + if(item && item->data) { + tsk_string_t *string = item->data; + return tsk_stricmp(string->value, stringVal); + } + return -1; } /*== Predicate function to find tsip_header_t object by type. */ static int __pred_find_header_by_type(const tsk_list_item_t *item, const void *tsip_htype) { - if(item && item->data){ - tsip_header_t *header = item->data; - tsip_header_type_t htype = *((tsip_header_type_t*)tsip_htype); - return (header->type - htype); - } - return -1; + if(item && item->data) { + tsip_header_t *header = item->data; + tsip_header_type_t htype = *((tsip_header_type_t*)tsip_htype); + return (header->type - htype); + } + return -1; } tsip_message_t* tsip_message_create() { - return tsk_object_new(tsip_message_def_t, tsip_unknown); + return tsk_object_new(tsip_message_def_t, tsip_unknown); } tsip_request_t* tsip_request_create(const char* method, const tsip_uri_t* uri) { - return tsk_object_new(tsip_message_def_t, tsip_request, method, uri); + return tsk_object_new(tsip_message_def_t, tsip_request, method, uri); } tsip_response_t* tsip_response_create(const tsip_request_t* request, short status_code, const char* reason_phrase) { - return tsk_object_new(tsip_message_def_t, tsip_response, request, status_code, reason_phrase); + return tsk_object_new(tsip_message_def_t, tsip_response, request, status_code, reason_phrase); } int tsip_message_add_header(tsip_message_t *self, const tsip_header_t *hdr) { - #define ADD_HEADER(type, field) \ +#define ADD_HEADER(type, field) \ case tsip_htype_##type: \ { \ if(!self->field) \ @@ -95,401 +95,450 @@ int tsip_message_add_header(tsip_message_t *self, const tsip_header_t *hdr) } \ break; \ } - - if(self && hdr){ - tsip_header_t *header = tsk_object_ref((void*)hdr); - - switch(header->type){ - ADD_HEADER(Via, firstVia); - ADD_HEADER(From, From); - ADD_HEADER(To, To); - ADD_HEADER(Contact, Contact); - ADD_HEADER(Call_ID, Call_ID); - ADD_HEADER(CSeq, CSeq); - ADD_HEADER(Expires, Expires); - ADD_HEADER(Content_Type, Content_Type); - ADD_HEADER(Content_Length, Content_Length); - - default: break; - } - - tsk_list_push_back_data(self->headers, (void**)&header); - - return 0; - } - return -1; + + if(self && hdr) { + tsip_header_t *header = tsk_object_ref((void*)hdr); + + switch(header->type) { + ADD_HEADER(Via, firstVia); + ADD_HEADER(From, From); + ADD_HEADER(To, To); + ADD_HEADER(Contact, Contact); + ADD_HEADER(Call_ID, Call_ID); + ADD_HEADER(CSeq, CSeq); + ADD_HEADER(Expires, Expires); + ADD_HEADER(Content_Type, Content_Type); + ADD_HEADER(Content_Length, Content_Length); + + default: + break; + } + + tsk_list_push_back_data(self->headers, (void**)&header); + + return 0; + } + return -1; } int tsip_message_add_headers(tsip_message_t *self, ...) { - const tsk_object_def_t* objdef; - tsip_header_t *header; - va_list ap; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - va_start(ap, self); - while((objdef = va_arg(ap, const tsk_object_def_t*))){ - if((header = tsk_object_new_2(objdef, &ap))){ - tsip_message_add_header(self, header); - TSK_OBJECT_SAFE_FREE(header); - } - } - va_end(ap); - - return 0; + const tsk_object_def_t* objdef; + tsip_header_t *header; + va_list ap; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + va_start(ap, self); + while((objdef = va_arg(ap, const tsk_object_def_t*))) { + if((header = tsk_object_new_2(objdef, &ap))) { + tsip_message_add_header(self, header); + TSK_OBJECT_SAFE_FREE(header); + } + } + va_end(ap); + + return 0; } int tsip_message_add_content(tsip_message_t *self, const char* content_type, const void* content, tsk_size_t size) { - if(self){ - if(content_type){ - TSK_OBJECT_SAFE_FREE(self->Content_Type); - } - TSK_OBJECT_SAFE_FREE(self->Content_Length); - TSK_OBJECT_SAFE_FREE(self->Content); - - if(content_type){ - TSIP_MESSAGE_ADD_HEADER(self, TSIP_HEADER_CONTENT_TYPE_VA_ARGS(content_type)); - } - TSIP_MESSAGE_ADD_HEADER(self, TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(size)); - self->Content = tsk_buffer_create(content, size); - - return 0; - } - return -1; + if(self) { + if(content_type) { + TSK_OBJECT_SAFE_FREE(self->Content_Type); + } + TSK_OBJECT_SAFE_FREE(self->Content_Length); + TSK_OBJECT_SAFE_FREE(self->Content); + + if(content_type) { + TSIP_MESSAGE_ADD_HEADER(self, TSIP_HEADER_CONTENT_TYPE_VA_ARGS(content_type)); + } + TSIP_MESSAGE_ADD_HEADER(self, TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(size)); + self->Content = tsk_buffer_create(content, size); + + return 0; + } + return -1; } const tsip_header_t *tsip_message_get_headerAt(const tsip_message_t *self, tsip_header_type_t type, tsk_size_t index) { - /* Do not forget to update tinyWRAP::SipMessage::getHeaderAt() */ - tsk_size_t pos = 0; - const tsk_list_item_t *item; - const tsip_header_t* hdr = tsk_null; - - if(self){ - switch(type) - { - case tsip_htype_Via: - if(index == 0){ - hdr = (const tsip_header_t*)self->firstVia; - goto bail; - }else pos++; break; - case tsip_htype_From: - if(index == 0){ - hdr = (const tsip_header_t*)self->From; - goto bail; - }else pos++; break; - case tsip_htype_To: - if(index == 0){ - hdr = (const tsip_header_t*)self->To; - goto bail; - }else pos++; break; - case tsip_htype_Contact: - if(index == 0){ - hdr = (const tsip_header_t*)self->Contact; - goto bail; - }else pos++; break; - case tsip_htype_Call_ID: - if(index == 0){ - hdr = (const tsip_header_t*)self->Call_ID; - goto bail; - }else pos++; break; - case tsip_htype_CSeq: - if(index == 0){ - hdr = (const tsip_header_t*)self->CSeq; - goto bail; - }else pos++; break; - case tsip_htype_Expires: - if(index == 0){ - hdr = (const tsip_header_t*)self->Expires; - goto bail; - }else pos++; break; - case tsip_htype_Content_Type: - if(index == 0){ - hdr = (const tsip_header_t*)self->Content_Type; - goto bail; - }else pos++; break; - case tsip_htype_Content_Length: - if(index == 0){ - hdr = (const tsip_header_t*)self->Content_Length; - goto bail; - }else pos++; break; - default: - break; - } - - tsk_list_foreach(item, self->headers){ - if(!__pred_find_header_by_type(item, &type)){ - if(pos++ >= index){ - hdr = item->data; - break; - } - } - } - } + /* Do not forget to update tinyWRAP::SipMessage::getHeaderAt() */ + tsk_size_t pos = 0; + const tsk_list_item_t *item; + const tsip_header_t* hdr = tsk_null; + + if(self) { + switch(type) { + case tsip_htype_Via: + if(index == 0) { + hdr = (const tsip_header_t*)self->firstVia; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_From: + if(index == 0) { + hdr = (const tsip_header_t*)self->From; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_To: + if(index == 0) { + hdr = (const tsip_header_t*)self->To; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_Contact: + if(index == 0) { + hdr = (const tsip_header_t*)self->Contact; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_Call_ID: + if(index == 0) { + hdr = (const tsip_header_t*)self->Call_ID; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_CSeq: + if(index == 0) { + hdr = (const tsip_header_t*)self->CSeq; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_Expires: + if(index == 0) { + hdr = (const tsip_header_t*)self->Expires; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_Content_Type: + if(index == 0) { + hdr = (const tsip_header_t*)self->Content_Type; + goto bail; + } + else { + pos++; + } + break; + case tsip_htype_Content_Length: + if(index == 0) { + hdr = (const tsip_header_t*)self->Content_Length; + goto bail; + } + else { + pos++; + } + break; + default: + break; + } + + tsk_list_foreach(item, self->headers) { + if(!__pred_find_header_by_type(item, &type)) { + if(pos++ >= index) { + hdr = item->data; + break; + } + } + } + } bail: - return hdr; + return hdr; } const tsip_header_t *tsip_message_get_headerLast(const tsip_message_t *self, tsip_header_type_t type) { - const tsip_header_t *hdr, *last = tsk_null; - tsk_size_t index = 0; - while((hdr = tsip_message_get_headerAt(self, type, index++))){ - last = hdr; - } - return last; + const tsip_header_t *hdr, *last = tsk_null; + tsk_size_t index = 0; + while((hdr = tsip_message_get_headerAt(self, type, index++))) { + last = hdr; + } + return last; } const tsip_header_t *tsip_message_get_header(const tsip_message_t *self, tsip_header_type_t type) { - return tsip_message_get_headerAt(self, type, 0); + return tsip_message_get_headerAt(self, type, 0); } /** -* Indicates whether the sepecified method is listed in the SIP 'Allow' header. +* Indicates whether the sepecified method is listed in the SIP 'Allow' header. * -* @param [in,out] self The SIP message holding the 'Allow' header. -* @param [in,out] method The method to look for. +* @param [in,out] self The SIP message holding the 'Allow' header. +* @param [in,out] method The method to look for. * -* @return @a tsk_true if succeed and @a tsk_false otherwise. +* @return @a tsk_true if succeed and @a tsk_false otherwise. */ tsk_bool_t tsip_message_allowed(const tsip_message_t *self, const char* method) { - int index = 0; - tsip_header_Allow_t *hdr_allow; - - if(self){ - while( (hdr_allow = (tsip_header_Allow_t*)tsip_message_get_headerAt(self, tsip_htype_Allow, index++)) ){ - if(tsk_list_find_item_by_pred(hdr_allow->methods, __pred_find_string_by_value, method)){ - return tsk_true; - } - } - } - return tsk_false; + int index = 0; + tsip_header_Allow_t *hdr_allow; + + if(self) { + while( (hdr_allow = (tsip_header_Allow_t*)tsip_message_get_headerAt(self, tsip_htype_Allow, index++)) ) { + if(tsk_list_find_item_by_pred(hdr_allow->methods, __pred_find_string_by_value, method)) { + return tsk_true; + } + } + } + return tsk_false; } tsk_bool_t tsip_message_supported(const tsip_message_t *self, const char* option) { - int index = 0; - tsip_header_Supported_t *hdr_supported; - - if(self){ - while( (hdr_supported = (tsip_header_Supported_t*)tsip_message_get_headerAt(self, tsip_htype_Supported, index++)) ){ - if(tsk_list_find_item_by_pred(hdr_supported->options, __pred_find_string_by_value, option)){ - return tsk_true; - } - } - } - return tsk_false; + int index = 0; + tsip_header_Supported_t *hdr_supported; + + if(self) { + while( (hdr_supported = (tsip_header_Supported_t*)tsip_message_get_headerAt(self, tsip_htype_Supported, index++)) ) { + if(tsk_list_find_item_by_pred(hdr_supported->options, __pred_find_string_by_value, option)) { + return tsk_true; + } + } + } + return tsk_false; } tsk_bool_t tsip_message_required(const tsip_message_t *self, const char* option) { - int index = 0; - tsip_header_Require_t *hdr_require; - - if(self){ - while( (hdr_require = (tsip_header_Require_t*)tsip_message_get_headerAt(self, tsip_htype_Require, index++)) ){ - if(tsk_list_find_item_by_pred(hdr_require->options, __pred_find_string_by_value, option)){ - return tsk_true; - } - } - } - return tsk_false; + int index = 0; + tsip_header_Require_t *hdr_require; + + if(self) { + while( (hdr_require = (tsip_header_Require_t*)tsip_message_get_headerAt(self, tsip_htype_Require, index++)) ) { + if(tsk_list_find_item_by_pred(hdr_require->options, __pred_find_string_by_value, option)) { + return tsk_true; + } + } + } + return tsk_false; } int64_t tsip_message_getExpires(const tsip_message_t *self) -{ - if(self){ - if(self->Expires){ - return self->Expires->delta_seconds; - } - - // FIXME: You MUST choose the right contact - if(self->Contact){ - return self->Contact->expires; - } - } - return -1; +{ + if(self) { + if(self->Expires) { + return self->Expires->delta_seconds; + } + + // FIXME: You MUST choose the right contact + if(self->Contact) { + return self->Contact->expires; + } + } + return -1; } uint32_t tsip_message_getContent_length(const tsip_message_t *self) { - return (self && self->Content_Length) ? self->Content_Length->length : 0; + return (self && self->Content_Length) ? self->Content_Length->length : 0; } int tsip_message_tostring(const tsip_message_t *self, tsk_buffer_t *output) { - if(!self || !output){ - return -1; - } - - if(TSIP_MESSAGE_IS_REQUEST(self)){ - /*Method SP Request_URI SP SIP_Version CRLF*/ - /* Method */ - tsk_buffer_append_2(output, "%s ", self->line.request.method); - /* Request URI (without quotes but with params)*/ - tsip_uri_serialize(self->line.request.uri, tsk_true, tsk_false, output); - /* SIP VERSION */ - tsk_buffer_append_2(output, " %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT); - } - else{ - /*SIP_Version SP Status_Code SP Reason_Phrase CRLF*/ - tsk_buffer_append_2(output, "%s %hi %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT, TSIP_RESPONSE_CODE(self), TSIP_RESPONSE_PHRASE(self)); - } - - /* First Via */ - if(self->firstVia){ - tsip_header_serialize(TSIP_HEADER(self->firstVia), output); - } - - /* From */ - if(self->From){ - tsip_header_serialize(TSIP_HEADER(self->From), output); - } - /* To */ - if(self->To){ - tsip_header_serialize(TSIP_HEADER(self->To), output); - } - /* Contact */ - if(self->Contact){ - tsip_header_serialize(TSIP_HEADER(self->Contact), output); - } - /* Call_id */ - if(self->Call_ID){ - tsip_header_serialize(TSIP_HEADER(self->Call_ID), output); - } - /* CSeq */ - if(self->CSeq){ - tsip_header_serialize(TSIP_HEADER(self->CSeq), output); - } - /* Expires */ - if(self->Expires){ - tsip_header_serialize(TSIP_HEADER(self->Expires), output); - } - /* Content-Type */ - if(self->Content_Type){ - tsip_header_serialize(TSIP_HEADER(self->Content_Type), output); - } - /* Content-Length*/ - if(self->Content_Length){ - tsip_header_serialize(TSIP_HEADER(self->Content_Length), output); - } - - /* All other headers */ - { - tsk_list_item_t *item; - tsk_list_foreach(item, self->headers){ - tsip_header_serialize(TSIP_HEADER(item->data), output); - } - } - - /* EMPTY LINE */ - tsk_buffer_append(output, "\r\n", 2); - - /* CONTENT */ - if(TSIP_MESSAGE_HAS_CONTENT(self)){ - tsk_buffer_append(output, TSK_BUFFER_TO_STRING(self->Content), TSK_BUFFER_SIZE(self->Content)); - } - - return 0; + if(!self || !output) { + return -1; + } + + if(TSIP_MESSAGE_IS_REQUEST(self)) { + /*Method SP Request_URI SP SIP_Version CRLF*/ + /* Method */ + tsk_buffer_append_2(output, "%s ", self->line.request.method); + /* Request URI (without quotes but with params)*/ + tsip_uri_serialize(self->line.request.uri, tsk_true, tsk_false, output); + /* SIP VERSION */ + tsk_buffer_append_2(output, " %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT); + } + else { + /*SIP_Version SP Status_Code SP Reason_Phrase CRLF*/ + tsk_buffer_append_2(output, "%s %hi %s\r\n", TSIP_MESSAGE_VERSION_DEFAULT, TSIP_RESPONSE_CODE(self), TSIP_RESPONSE_PHRASE(self)); + } + + /* First Via */ + if(self->firstVia) { + tsip_header_serialize(TSIP_HEADER(self->firstVia), output); + } + + /* From */ + if(self->From) { + tsip_header_serialize(TSIP_HEADER(self->From), output); + } + /* To */ + if(self->To) { + tsip_header_serialize(TSIP_HEADER(self->To), output); + } + /* Contact */ + if(self->Contact) { + tsip_header_serialize(TSIP_HEADER(self->Contact), output); + } + /* Call_id */ + if(self->Call_ID) { + tsip_header_serialize(TSIP_HEADER(self->Call_ID), output); + } + /* CSeq */ + if(self->CSeq) { + tsip_header_serialize(TSIP_HEADER(self->CSeq), output); + } + /* Expires */ + if(self->Expires) { + tsip_header_serialize(TSIP_HEADER(self->Expires), output); + } + /* Content-Type */ + if(self->Content_Type) { + tsip_header_serialize(TSIP_HEADER(self->Content_Type), output); + } + /* Content-Length*/ + if(self->Content_Length) { + tsip_header_serialize(TSIP_HEADER(self->Content_Length), output); + } + + /* All other headers */ + { + tsk_list_item_t *item; + tsk_list_foreach(item, self->headers) { + tsip_header_serialize(TSIP_HEADER(item->data), output); + } + } + + /* EMPTY LINE */ + tsk_buffer_append(output, "\r\n", 2); + + /* CONTENT */ + if(TSIP_MESSAGE_HAS_CONTENT(self)) { + tsk_buffer_append(output, TSK_BUFFER_TO_STRING(self->Content), TSK_BUFFER_SIZE(self->Content)); + } + + return 0; } tsip_request_type_t tsip_request_get_type(const char* method) { - if(tsk_strnullORempty(method)){ - return tsip_NONE; - } - - if(tsk_striequals(method, "ACK")){ - return tsip_ACK; - }else if(tsk_striequals(method, "BYE")){ - return tsip_BYE; - }else if(tsk_striequals(method, "CANCEL")){ - return tsip_CANCEL; - }else if(tsk_striequals(method, "INVITE")){ - return tsip_INVITE; - }else if(tsk_striequals(method, "OPTIONS")){ - return tsip_OPTIONS; - }else if(tsk_striequals(method, "REGISTER")){ - return tsip_REGISTER; - }else if(tsk_striequals(method, "SUBSCRIBE")){ - return tsip_SUBSCRIBE; - }else if(tsk_striequals(method, "NOTIFY")){ - return tsip_NOTIFY; - }else if(tsk_striequals(method, "REFER")){ - return tsip_REFER; - }else if(tsk_striequals(method, "INFO")){ - return tsip_INFO; - }else if(tsk_striequals(method, "UPDATE")){ - return tsip_UPDATE; - }else if(tsk_striequals(method, "MESSAGE")){ - return tsip_MESSAGE; - }else if(tsk_striequals(method, "PUBLISH")){ - return tsip_PUBLISH; - }else if(tsk_striequals(method, "PRACK")){ - return tsip_PRACK; - } - - return tsip_NONE; + if(tsk_strnullORempty(method)) { + return tsip_NONE; + } + + if(tsk_striequals(method, "ACK")) { + return tsip_ACK; + } + else if(tsk_striequals(method, "BYE")) { + return tsip_BYE; + } + else if(tsk_striequals(method, "CANCEL")) { + return tsip_CANCEL; + } + else if(tsk_striequals(method, "INVITE")) { + return tsip_INVITE; + } + else if(tsk_striequals(method, "OPTIONS")) { + return tsip_OPTIONS; + } + else if(tsk_striequals(method, "REGISTER")) { + return tsip_REGISTER; + } + else if(tsk_striequals(method, "SUBSCRIBE")) { + return tsip_SUBSCRIBE; + } + else if(tsk_striequals(method, "NOTIFY")) { + return tsip_NOTIFY; + } + else if(tsk_striequals(method, "REFER")) { + return tsip_REFER; + } + else if(tsk_striequals(method, "INFO")) { + return tsip_INFO; + } + else if(tsk_striequals(method, "UPDATE")) { + return tsip_UPDATE; + } + else if(tsk_striequals(method, "MESSAGE")) { + return tsip_MESSAGE; + } + else if(tsk_striequals(method, "PUBLISH")) { + return tsip_PUBLISH; + } + else if(tsk_striequals(method, "PRACK")) { + return tsip_PRACK; + } + + return tsip_NONE; } tsip_request_t *tsip_request_new(const char* method, const tsip_uri_t *request_uri, const tsip_uri_t *from, const tsip_uri_t *to, const char *call_id, int32_t cseq) { - tsip_request_t* request; - - /* RFC 3261 8.1.1 Generating the Request - A valid SIP request formulated by a UAC MUST, at a minimum, contain - the following header fields: To, From, CSeq, Call-ID, Max-Forwards, - and Via; all of these header fields are mandatory in all SIP - requests. These six header fields are the fundamental building - blocks of a SIP message, as they jointly provide for most of the - critical message routing services including the addressing of - messages, the routing of responses, limiting message propagation, - ordering of messages, and the unique identification of transactions. - These header fields are in addition to the mandatory request line, - which contains the method, Request-URI, and SIP version. - */ - - if((request = tsip_request_create(method, request_uri))){ - tsip_message_add_headers(request, - TSIP_HEADER_TO_VA_ARGS(to?to->display_name:tsk_null, to, tsk_null), - TSIP_HEADER_FROM_VA_ARGS(from?from->display_name:tsk_null, from, tsk_null), - TSIP_HEADER_CSEQ_VA_ARGS(cseq, method), - TSIP_HEADER_CALL_ID_VA_ARGS(call_id), - TSIP_HEADER_MAX_FORWARDS_VA_ARGS(TSIP_HEADER_MAX_FORWARDS_DEFAULT), - /* Via will be added by the transport layer */ - /* TSIP_HEADER_USER_AGENT_VA_ARGS(TSIP_HEADER_USER_AGENT_DEFAULT), */ - TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), - - tsk_null); - } - - return request; + tsip_request_t* request; + + /* RFC 3261 8.1.1 Generating the Request + A valid SIP request formulated by a UAC MUST, at a minimum, contain + the following header fields: To, From, CSeq, Call-ID, Max-Forwards, + and Via; all of these header fields are mandatory in all SIP + requests. These six header fields are the fundamental building + blocks of a SIP message, as they jointly provide for most of the + critical message routing services including the addressing of + messages, the routing of responses, limiting message propagation, + ordering of messages, and the unique identification of transactions. + These header fields are in addition to the mandatory request line, + which contains the method, Request-URI, and SIP version. + */ + + if((request = tsip_request_create(method, request_uri))) { + tsip_message_add_headers(request, + TSIP_HEADER_TO_VA_ARGS(to?to->display_name:tsk_null, to, tsk_null), + TSIP_HEADER_FROM_VA_ARGS(from?from->display_name:tsk_null, from, tsk_null), + TSIP_HEADER_CSEQ_VA_ARGS(cseq, method), + TSIP_HEADER_CALL_ID_VA_ARGS(call_id), + TSIP_HEADER_MAX_FORWARDS_VA_ARGS(TSIP_HEADER_MAX_FORWARDS_DEFAULT), + /* Via will be added by the transport layer */ + /* TSIP_HEADER_USER_AGENT_VA_ARGS(TSIP_HEADER_USER_AGENT_DEFAULT), */ + TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), + + tsk_null); + } + + return request; } tsip_response_t *tsip_response_new(short status_code, const char* reason_phrase, const tsip_request_t *request) { - tsip_response_t *response = tsk_null; + tsip_response_t *response = tsk_null; - if(request){ - if((response = tsip_response_create(request, status_code, reason_phrase))){ - tsip_message_add_headers(response, - /* TSIP_HEADER_USER_AGENT_VA_ARGS(TSIP_HEADER_USER_AGENT_DEFAULT), */ /* To be compliant with OMA SIMPLE IM v1.0*/ - TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), + if(request) { + if((response = tsip_response_create(request, status_code, reason_phrase))) { + tsip_message_add_headers(response, + /* TSIP_HEADER_USER_AGENT_VA_ARGS(TSIP_HEADER_USER_AGENT_DEFAULT), */ /* To be compliant with OMA SIMPLE IM v1.0*/ + TSIP_HEADER_CONTENT_LENGTH_VA_ARGS(0), - tsk_null); - } - } + tsk_null); + } + } - return response; + return response; } @@ -508,147 +557,142 @@ tsip_response_t *tsip_response_new(short status_code, const char* reason_phrase, */ static tsk_object_t* tsip_message_ctor(tsk_object_t *self, va_list * app) { - tsip_message_t *message = self; - if(message) - { - message->type = va_arg(*app, tsip_message_type_t); - message->headers = tsk_list_create(); - message->local_fd = TNET_INVALID_FD; - message->line.request.request_type = tsip_NONE; - - - switch(message->type) - { - case tsip_unknown: - { - break; - } + tsip_message_t *message = self; + if(message) { + message->type = va_arg(*app, tsip_message_type_t); + message->headers = tsk_list_create(); + message->local_fd = TNET_INVALID_FD; + message->line.request.request_type = tsip_NONE; - case tsip_request: - { - message->line.request.method = tsk_strdup(va_arg(*app, const char*)); - message->line.request.uri = tsk_object_ref((void*)va_arg(*app, const tsip_uri_t*)); - message->line.request.request_type = tsip_request_get_type(message->line.request.method); - break; - } + switch(message->type) { + case tsip_unknown: { + break; + } - case tsip_response: - { - const tsip_request_t* request = va_arg(*app, const tsip_request_t*); + case tsip_request: { + message->line.request.method = tsk_strdup(va_arg(*app, const char*)); + message->line.request.uri = tsk_object_ref((void*)va_arg(*app, const tsip_uri_t*)); + + message->line.request.request_type = tsip_request_get_type(message->line.request.method); + break; + } + + case tsip_response: { + const tsip_request_t* request = va_arg(*app, const tsip_request_t*); #if defined(__GNUC__) - message->line.response.status_code = (short)va_arg(*app, int); + message->line.response.status_code = (short)va_arg(*app, int); #else - message->line.response.status_code = va_arg(*app, short); + message->line.response.status_code = va_arg(*app, short); #endif - message->line.response.reason_phrase = tsk_strdup(va_arg(*app, const char*)); - - /* Copy network information */ - message->local_fd = request->local_fd; - message->remote_addr = request->remote_addr; - message->src_net_type = request->src_net_type; - message->dst_net_type = request->dst_net_type; - - /* - RFC 3261 - 8.2.6.2 Headers and Tags - - The From field of the response MUST equal the From header field of - the request. The Call-ID header field of the response MUST equal the - Call-ID header field of the request. The CSeq header field of the - response MUST equal the CSeq field of the request. The Via header - field values in the response MUST equal the Via header field values - in the request and MUST maintain the same ordering. - - If a request contained a To tag in the request, the To header field - in the response MUST equal that of the request. However, if the To - header field in the request did not contain a tag, the URI in the To - header field in the response MUST equal the URI in the To header - field; additionally, the UAS MUST add a tag to the To header field in - the response (with the exception of the 100 (Trying) response, in - which a tag MAY be present). This serves to identify the UAS that is - responding, possibly resulting in a component of a dialog ID. The - same tag MUST be used for all responses to that request, both final - and provisional (again excepting the 100 (Trying)). Procedures for - the generation of tags are defined in Section 19.3. - */ - message->From = tsk_object_ref((void*)request->From); - message->Call_ID = tsk_object_ref((void*)request->Call_ID); - message->CSeq = tsk_object_ref((void*)request->CSeq); - message->firstVia = tsk_object_ref((void*)request->firstVia); - /* All other VIAs */ - if(message->firstVia){ - tsk_size_t index = 1; - const tsip_header_t * via; - while((via = tsip_message_get_headerAt(request, tsip_htype_Via, index++))){ - tsip_message_add_header(message, via); - } - } - /* Record routes */ - { - tsk_size_t index = 0; - const tsip_header_t *record_route; - while((record_route = tsip_message_get_headerAt(request, tsip_htype_Record_Route, index++))){ - tsip_message_add_header(message, record_route); - } - } - message->To = tsk_object_ref((void*)request->To); - - break; - } - } - } - else - { - TSK_DEBUG_ERROR("Failed to create new sip message."); - } - return self; + message->line.response.reason_phrase = tsk_strdup(va_arg(*app, const char*)); + + /* Copy network information */ + message->local_fd = request->local_fd; + message->remote_addr = request->remote_addr; + message->src_net_type = request->src_net_type; + message->dst_net_type = request->dst_net_type; + + /* + RFC 3261 - 8.2.6.2 Headers and Tags + + The From field of the response MUST equal the From header field of + the request. The Call-ID header field of the response MUST equal the + Call-ID header field of the request. The CSeq header field of the + response MUST equal the CSeq field of the request. The Via header + field values in the response MUST equal the Via header field values + in the request and MUST maintain the same ordering. + + If a request contained a To tag in the request, the To header field + in the response MUST equal that of the request. However, if the To + header field in the request did not contain a tag, the URI in the To + header field in the response MUST equal the URI in the To header + field; additionally, the UAS MUST add a tag to the To header field in + the response (with the exception of the 100 (Trying) response, in + which a tag MAY be present). This serves to identify the UAS that is + responding, possibly resulting in a component of a dialog ID. The + same tag MUST be used for all responses to that request, both final + and provisional (again excepting the 100 (Trying)). Procedures for + the generation of tags are defined in Section 19.3. + */ + message->From = tsk_object_ref((void*)request->From); + message->Call_ID = tsk_object_ref((void*)request->Call_ID); + message->CSeq = tsk_object_ref((void*)request->CSeq); + message->firstVia = tsk_object_ref((void*)request->firstVia); + /* All other VIAs */ + if(message->firstVia) { + tsk_size_t index = 1; + const tsip_header_t * via; + while((via = tsip_message_get_headerAt(request, tsip_htype_Via, index++))) { + tsip_message_add_header(message, via); + } + } + /* Record routes */ + { + tsk_size_t index = 0; + const tsip_header_t *record_route; + while((record_route = tsip_message_get_headerAt(request, tsip_htype_Record_Route, index++))) { + tsip_message_add_header(message, record_route); + } + } + message->To = tsk_object_ref((void*)request->To); + + break; + } + } + } + else { + TSK_DEBUG_ERROR("Failed to create new sip message."); + } + return self; } /**@ingroup tsip_message_group */ static tsk_object_t* tsip_message_dtor(tsk_object_t *self) { - tsip_message_t *message = self; - if(message){ - if(TSIP_MESSAGE_IS_REQUEST(message)){ - TSK_FREE(message->line.request.method); - TSK_OBJECT_SAFE_FREE(message->line.request.uri); - } - else if(TSIP_MESSAGE_IS_RESPONSE(message)){ - TSK_FREE(message->line.response.reason_phrase); - } - - TSK_FREE(message->sip_version); - - TSK_OBJECT_SAFE_FREE(message->Call_ID); - TSK_OBJECT_SAFE_FREE(message->Contact); - TSK_OBJECT_SAFE_FREE(message->Content_Length); - TSK_OBJECT_SAFE_FREE(message->Content_Type); - TSK_OBJECT_SAFE_FREE(message->CSeq); - TSK_OBJECT_SAFE_FREE(message->firstVia); - TSK_OBJECT_SAFE_FREE(message->From); - TSK_OBJECT_SAFE_FREE(message->Expires); - TSK_OBJECT_SAFE_FREE(message->To); - - TSK_OBJECT_SAFE_FREE(message->Content); - - TSK_OBJECT_SAFE_FREE(message->headers); - - TSK_FREE(message->sigcomp_id); - - TSK_FREE(message->dst_address); - } - else TSK_DEBUG_ERROR("Null SIP message."); - - return self; + tsip_message_t *message = self; + if(message) { + if(TSIP_MESSAGE_IS_REQUEST(message)) { + TSK_FREE(message->line.request.method); + TSK_OBJECT_SAFE_FREE(message->line.request.uri); + } + else if(TSIP_MESSAGE_IS_RESPONSE(message)) { + TSK_FREE(message->line.response.reason_phrase); + } + + TSK_FREE(message->sip_version); + + TSK_OBJECT_SAFE_FREE(message->Call_ID); + TSK_OBJECT_SAFE_FREE(message->Contact); + TSK_OBJECT_SAFE_FREE(message->Content_Length); + TSK_OBJECT_SAFE_FREE(message->Content_Type); + TSK_OBJECT_SAFE_FREE(message->CSeq); + TSK_OBJECT_SAFE_FREE(message->firstVia); + TSK_OBJECT_SAFE_FREE(message->From); + TSK_OBJECT_SAFE_FREE(message->Expires); + TSK_OBJECT_SAFE_FREE(message->To); + + TSK_OBJECT_SAFE_FREE(message->Content); + + TSK_OBJECT_SAFE_FREE(message->headers); + + TSK_FREE(message->sigcomp_id); + + TSK_FREE(message->dst_address); + } + else { + TSK_DEBUG_ERROR("Null SIP message."); + } + + return self; } -static const tsk_object_def_t tsip_message_def_s = -{ - sizeof(tsip_message_t), - tsip_message_ctor, - tsip_message_dtor, - tsk_null +static const tsk_object_def_t tsip_message_def_s = { + sizeof(tsip_message_t), + tsip_message_ctor, + tsip_message_dtor, + tsk_null }; const tsk_object_def_t *tsip_message_def_t = &tsip_message_def_s; |