#if HAVE_CRT #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #endif //HAVE_CRT /* * Copyright (C) 2020, University of the Basque Country (UPV/EHU) * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com> * * The original file was part of Open Source Doubango Framework * Copyright (C) 2010-2011 Mamadou Diop. * Copyright (C) 2012 Doubango Telecom <http://doubango.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. * */ /**@file tsip_api_message.c * @brief Public short messaging (MESSAGE) functions. * * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> * */ #include <tinysip/tsip_ssession.h> #include "tinysip/api/tsip_api_message.h" #include "tinysip/dialogs/tsip_dialog_layer.h" #include "tinysip/dialogs/tsip_dialog_message.h" #include "tinymedia/content/tmedia_content_multipart.h" #include "tinysip/headers/tsip_header_Dummy.h" #include "tinysip/tsip_message.h" #include "tsip.h" #include "tsk_memory.h" #include "tsk_runnable.h" #include "tsk_debug.h" #define TSIP_MESSAGE_EVENT_CREATE( type) (tsip_message_event_t*)tsk_object_new(tsip_message_event_def_t, type) #define VALUE_CONTENT_TYPE_MESSAGE_LOCATION "application/vnd.3gpp.mcptt-location-info+xml" #define VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION "application/vnd.3gpp.mcptt-affiliation-command+xml" #define VALUE_CONTENT_TYPE_MESSAGE_MBMS "application/vnd.3gpp.mcptt-mbms-usage-info+xml" #define VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION "urn:urn-7:3gpp-service.ims.icsi.mcptt" #define VALUE_P_ASSERTED_SERVICE_MESSAGE_MBMS "urn:urn-7:3gpp-service.ims.icsi.mcptt" #define VALUE_CONTENT_TYPE_MULTIPART "multipart/mixed" extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app); #if HAVE_LIBXML2 static int register_xml_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) { xmlChar* nsListDup; xmlChar* prefix; xmlChar* href; xmlChar* next; nsListDup = xmlStrdup(nsList); if(nsListDup == NULL) { return(-1); } next = nsListDup; while(next != NULL) { /* skip spaces */ while((*next) == ' ') next++; if((*next) == '\0') break; /* find prefix */ prefix = next; next = (xmlChar*)xmlStrchr(next, '='); if(next == NULL) { xmlFree(nsListDup); return(-1); } *(next++) = '\0'; /* find href */ href = next; next = (xmlChar*)xmlStrchr(next, ' '); if(next != NULL) { *(next++) = '\0'; } if(href[0] == '\"' || href[0] == '\'') { href = href + 1; if(href[strlen(href) - 1] == '\"' || href[strlen(href) - 1] == '\'') href[strlen(href) - 1] = '\0'; } /* do register namespace */ if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) { xmlFree(nsListDup); return(-1); } } xmlFree(nsListDup); return(0); } #endif int tsip_message_event_signal(tsip_message_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage) { tsip_message_event_t* sipevent = TSIP_MESSAGE_EVENT_CREATE(type); tmedia_content_multipart_t* mp_content = tsk_null; tmedia_content_multipart_t* mp_content_sdp = tsk_null; tmedia_multipart_body_t* mp_body = tsk_null; char* boundary = tsk_null; const tsip_header_t* header =tsk_null; char* hdr_value=tsk_null; uint32_t local_ssrc = 0; char* psi_mbms_value=tsk_null; //tmedia_session_t* audio_session; //tsdp_message_t* sdp_ro = tsk_null; int con=0; char* sdp=tsk_null; tsip_message_t* sipmessage2=tsk_null; //if the messager is send if((((tsip_ssession_t*)ss)->media.type & tmedia_mcptt_location) == tmedia_mcptt_location){ tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location); }else if(tsk_strcmp(TSIP_MESSAGE_CONTENT_TYPE(sipmessage),VALUE_CONTENT_TYPE_MESSAGE_LOCATION)==0){//it receive message tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location); }else if( tsk_strcmp(TSIP_MESSAGE_CONTENT_TYPE(sipmessage),VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION)==0){//it receive message for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++) { const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header; if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0) { #if HAVE_CRT //Debug memory hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #else hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #endif //HAVE_CRT hdr_value=strdup(dummy_hdr->value); break; } /* else if(tsk_strcmp(dummy_hdr->name, "User-Agent") == 0) { len = tsk_strlen(dummy_hdr->value) + 19; hdr_value = (char *)malloc(len * sizeof(char)); tsk_sprintf(&hdr_value, "PoC-client/OMA_PCPS_1.0 %s", dummy_hdr->value); tsk_object_delete(dummy_hdr->value); }*/ } if((hdr_value)!=tsk_null && tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION)==0 ){ tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_affiliation); } TSK_FREE(hdr_value); }else if(tsk_striequals(VALUE_CONTENT_TYPE_MULTIPART, TSIP_MESSAGE_CONTENT_TYPE(sipmessage))){ //multipart/mixed boundary = tsip_header_get_param_value((tsip_header_t*)sipmessage->Content_Type, "boundary"); if(boundary != tsk_null) { mp_body = tmedia_content_multipart_body_parse(TSIP_MESSAGE_CONTENT_DATA(sipmessage), TSIP_MESSAGE_CONTENT_DATA_LENGTH(sipmessage), VALUE_CONTENT_TYPE_MULTIPART, boundary); if(mp_body != tsk_null) { mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_LOCATION); if(mp_content != tsk_null)//Location { //change de content for format location TSK_FREE(sipmessage->Content->data); if ((sipmessage->Content->data = (char*)tsk_calloc((mp_content->data_size) + 1, sizeof(uint8_t)))) { memcpy(sipmessage->Content->data, mp_content->data, mp_content->data_size); ((char *)sipmessage->Content->data)[mp_content->data_size]='\0'; } sipmessage->Content->size=mp_content->data_size; tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location); }else if(1){ mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION); if(mp_content != tsk_null )//Affiliation { for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++) { const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header; if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0) { #if HAVE_CRT //Debug memory hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #else hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #endif //HAVE_CRT hdr_value=strdup(dummy_hdr->value); break; } } if((hdr_value)!=tsk_null && tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION)==0 ){ //change de content for format affiliation //tsk_realloc(sipmessage->Content->data,mp_content->data_size); TSK_FREE(sipmessage->Content->data) sipmessage->Content->data=tsk_strndup(mp_content->data,mp_content->data_size); sipmessage->Content->size=mp_content->data_size; tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_affiliation); } } else{ tmedia_multipart_body_t* body = tsk_null; char* content_type_hdr = tsk_null; char* body_string = tsk_null; //mp_content is xml of MBMS mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_MBMS); //mp_content_sdp is the data in char* of SDP mp_content_sdp = tmedia_content_multipart_body_get_content(mp_body, "application/sdp"); if(mp_content != tsk_null && mp_content_sdp!=tsk_null)//MBMS service { for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++) { const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header; if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0) { #if HAVE_CRT //Debug memory hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #else hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char)); #endif //HAVE_CRT hdr_value=strdup(dummy_hdr->value); break; } } //SDP of MBMS message if(mp_content_sdp == tsk_null){ TSK_DEBUG_ERROR("content-type is not supportted"); return -3; } if((hdr_value)!=tsk_null && tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_MBMS)==0 ){ body = tmedia_content_multipart_body_create("multipart/mixed", tsk_null); if(body) { tmedia_content_multipart_body_add_content(body, mp_content_sdp); tmedia_content_multipart_body_add_content(body, mp_content); body_string =tmedia_content_multipart_body_tostring(body); content_type_hdr = tmedia_content_multipart_body_get_header(body); sipmessage2=tsip_message_create(); tsip_message_add_content(sipmessage2, content_type_hdr, body_string, tsk_strlen(body_string)); } /* //change de content for format MBMS tsk_realloc(sipmessage->Content->data,mp_content->data_size); strcpy(sipmessage->Content->data, mp_content->data); sipmessage->Content->size=mp_content->data_size; */ tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_mbms); } }else{ TSK_DEBUG_ERROR("The new message isn't valid."); tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message); } } } } }else{ tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message); } }else tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message); if(hdr_value) TSK_FREE(hdr_value); TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent); return 0; } int tsip_api_message_send_message(const tsip_ssession_handle_t *ss, ...) { const tsip_ssession_t* _ss; va_list ap; tsip_action_t* action; tsip_dialog_t* dialog; int ret = -1; if(!(_ss = ss) || !_ss->stack){ TSK_DEBUG_ERROR("Invalid parameter."); return ret; } /* Checks if the stack has been started */ if(!TSK_RUNNABLE(_ss->stack)->started){ TSK_DEBUG_ERROR("Stack not started."); return -2; } /* action */ va_start(ap, ss); if((action = _tsip_action_create(tsip_atype_message_send, &ap))){ if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss); } ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); tsk_object_unref(dialog); TSK_OBJECT_SAFE_FREE(action); } va_end(ap); return ret; } //Location int tsip_api_message_send_message_location(const tsip_ssession_handle_t *ss, ...) { const tsip_ssession_t* _ss; va_list ap; tsip_action_t* action; tsip_dialog_t* dialog; int ret = -1; if(!(_ss = ss) || !_ss->stack){ TSK_DEBUG_ERROR("Invalid parameter."); return ret; } /* Checks if the stack has been started */ if(!TSK_RUNNABLE(_ss->stack)->started){ TSK_DEBUG_ERROR("Stack not started."); return -2; } //This session is type MCPTT location ((tsip_ssession_t*)ss)->media.type=tmedia_mcptt_location; /* action */ va_start(ap, ss); if((action = _tsip_action_create(tsip_atype_message_send, &ap))){ if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss); } ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); tsk_object_unref(dialog); TSK_OBJECT_SAFE_FREE(action); } va_end(ap); return ret; } //MBMS int tsip_api_message_send_message_mbms(const tsip_ssession_handle_t *ss, ...) { const tsip_ssession_t* _ss; va_list ap; tsip_action_t* action; tsip_dialog_t* dialog; int ret = -1; if(!(_ss = ss) || !_ss->stack){ TSK_DEBUG_ERROR("Invalid parameter."); return ret; } /* Checks if the stack has been started */ if(!TSK_RUNNABLE(_ss->stack)->started){ TSK_DEBUG_ERROR("Stack not started."); return -2; } //This session is type MCPTT MBMS ((tsip_ssession_t*)ss)->media.type=tmedia_mcptt_mbms; /* action */ va_start(ap, ss); if((action = _tsip_action_create(tsip_atype_message_send, &ap))){ if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){ dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss); } ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action); tsk_object_unref(dialog); TSK_OBJECT_SAFE_FREE(action); } va_end(ap); return ret; } //======================================================== // SIP MESSAGE event object definition // static tsk_object_t* tsip_message_event_ctor(tsk_object_t * self, va_list * app) { tsip_message_event_t *sipevent = self; if(sipevent){ sipevent->type = va_arg(*app, tsip_message_event_type_t); } return self; } static tsk_object_t* tsip_message_event_dtor(tsk_object_t * self) { tsip_message_event_t *sipevent = self; if(sipevent){ tsip_event_deinit(TSIP_EVENT(sipevent)); } return self; } static int tsip_message_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) { return -1; } static const tsk_object_def_t tsip_message_event_def_s = { sizeof(tsip_message_event_t), tsip_message_event_ctor, tsip_message_event_dtor, tsip_message_event_cmp, }; const tsk_object_def_t *tsip_message_event_def_t = &tsip_message_event_def_s;