dialog_publish.c

00001 /*
00002  * $Id: ul_publish.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * pua_usrloc module - usrloc pua module
00005  *
00006  * Copyright (C) 2006 Voice Sistem S.R.L.
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <libxml/parser.h>
00029 #include <time.h>
00030 
00031 #include "../../parser/parse_expires.h"
00032 #include "../../parser/msg_parser.h"
00033 #include "../../str.h"
00034 #include "../../str_list.h"
00035 #include "../../name_alias.h"
00036 #include "../../socket_info.h"
00037 #include "../usrloc/usrloc.h"
00038 #include "../usrloc/ul_callback.h"
00039 #include "../../modules/tm/tm_load.h"
00040 #include "../pua/pua.h"
00041 #include "pua_dialoginfo.h"
00042 
00043 /* global modul parameters */
00044 extern int include_callid;
00045 extern int include_localremote;
00046 extern int include_tags;
00047 
00048 
00049 /* for debug purpose only */
00050 void print_publ(publ_info_t* p)
00051 {
00052         LM_DBG("publ:\n");
00053         LM_DBG("uri= %.*s\n", p->pres_uri->len, p->pres_uri->s);
00054         LM_DBG("id= %.*s\n", p->id.len, p->id.s);
00055         LM_DBG("expires= %d\n", p->expires);
00056 }       
00057 
00058 str* build_dialoginfo(char *state, str *entity, str *peer, str *callid, 
00059         unsigned int initiator, str *localtag, str *remotetag,
00060         str *localtarget, str *remotetarget)
00061 {
00062         xmlDocPtr  doc = NULL; 
00063         xmlNodePtr root_node = NULL;
00064         xmlNodePtr dialog_node = NULL;
00065         xmlNodePtr state_node = NULL;
00066         xmlNodePtr remote_node = NULL;
00067         xmlNodePtr local_node = NULL;
00068         xmlNodePtr tag_node = NULL;
00069         str *body= NULL;
00070         char buf[MAX_URI_SIZE+1];
00071 
00072         if (entity->len > MAX_URI_SIZE) {
00073                 LM_ERR("entity URI '%.*s' too long, maximum=%d\n",entity->len, entity->s, MAX_URI_SIZE);
00074                 return NULL;
00075         }
00076     memcpy(buf, entity->s, entity->len);
00077         buf[entity->len]= '\0';
00078 
00079         /* create the Publish body  */
00080         doc = xmlNewDoc(BAD_CAST "1.0");
00081         if(doc==0)
00082                 return NULL;
00083 
00084     root_node = xmlNewNode(NULL, BAD_CAST "dialog-info");
00085         if(root_node==0)
00086                 goto error;
00087     
00088         xmlDocSetRootElement(doc, root_node);
00089 
00090     xmlNewProp(root_node, BAD_CAST "xmlns",
00091                         BAD_CAST "urn:ietf:params:xml:ns:dialog-info");
00092         /* we set the version to 0 but it should be set to the correct value
00093        in the pua module */
00094         xmlNewProp(root_node, BAD_CAST "version",
00095                         BAD_CAST "0");
00096         xmlNewProp(root_node, BAD_CAST  "state",
00097                         BAD_CAST "full" );
00098         xmlNewProp(root_node, BAD_CAST "entity", 
00099                         BAD_CAST buf);
00100 
00101         /* RFC 3245 differs between id and call-id. For example if a call
00102            is forked and 2 early dialogs are established, we should send 2
00103             PUBLISH requests, both have the same call-id but different id.
00104             Thus, id could be for example derived from the totag.
00105 
00106             Currently the dialog module does not support multiple dialogs.
00107             Thus, it does no make sense to differ here between multiple dialog.
00108             Thus, id and call-id will be populated identically */
00109 
00110         /* dialog tag */
00111         dialog_node =xmlNewChild(root_node, NULL, BAD_CAST "dialog", NULL) ;
00112         if( dialog_node ==NULL)
00113         {
00114                 LM_ERR("while adding child\n");
00115                 goto error;
00116         }
00117 
00118         if (callid->len > MAX_URI_SIZE) {
00119                 LM_ERR("call-id '%.*s' too long, maximum=%d\n", callid->len, callid->s, MAX_URI_SIZE);
00120                 return NULL;
00121         }
00122     memcpy(buf, callid->s, callid->len);
00123         buf[callid->len]= '\0';
00124 
00125         xmlNewProp(dialog_node, BAD_CAST "id", BAD_CAST buf);
00126         if (include_callid) {
00127                 xmlNewProp(dialog_node, BAD_CAST "call-id", BAD_CAST buf);
00128         }
00129         if (include_tags) {
00130                 if (localtag && localtag->s) {
00131                         if (localtag->len > MAX_URI_SIZE) {
00132                                 LM_ERR("localtag '%.*s' too long, maximum=%d\n", localtag->len, localtag->s, MAX_URI_SIZE);
00133                                 return NULL;
00134                         }
00135                     memcpy(buf, localtag->s, localtag->len);
00136                         buf[localtag->len]= '\0';
00137                         xmlNewProp(dialog_node, BAD_CAST "local-tag", BAD_CAST buf);
00138                 }
00139                 if (remotetag && remotetag->s) {
00140                         if (remotetag->len > MAX_URI_SIZE) {
00141                                 LM_ERR("remotetag '%.*s' too long, maximum=%d\n", remotetag->len, remotetag->s, MAX_URI_SIZE);
00142                                 return NULL;
00143                         }
00144                     memcpy(buf, remotetag->s, remotetag->len);
00145                         buf[remotetag->len]= '\0';
00146                         xmlNewProp(dialog_node, BAD_CAST "remote-tag", BAD_CAST buf);
00147                 }
00148         }
00149 
00150         if (initiator) {
00151                 xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "initiator");
00152         }else {
00153                 xmlNewProp(dialog_node, BAD_CAST "direction", BAD_CAST "recipient");
00154         }
00155 
00156         /* state tag */
00157         state_node = xmlNewChild(dialog_node, NULL, BAD_CAST "state", BAD_CAST state) ;
00158         if( state_node ==NULL)
00159         {
00160                 LM_ERR("while adding child\n");
00161                 goto error;
00162         }
00163 
00164         if (include_localremote) {
00165                 /* remote tag*/ 
00166                 remote_node = xmlNewChild(dialog_node, NULL, BAD_CAST "remote", NULL) ;
00167                 if( remote_node ==NULL)
00168                 {
00169                         LM_ERR("while adding child\n");
00170                         goto error;
00171                 }
00172 
00173                 if (peer->len > MAX_URI_SIZE) {
00174                         LM_ERR("peer '%.*s' too long, maximum=%d\n", peer->len, peer->s, MAX_URI_SIZE);
00175                         return NULL;
00176                 }
00177         memcpy(buf, peer->s, peer->len);
00178                 buf[peer->len]= '\0';
00179 
00180                 tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "identity", BAD_CAST buf) ;
00181                 if( tag_node ==NULL)
00182                 {
00183                         LM_ERR("while adding child\n");
00184                         goto error;
00185                 }
00186                 tag_node = xmlNewChild(remote_node, NULL, BAD_CAST "target", NULL) ;
00187                 if( tag_node ==NULL)
00188                 {
00189                         LM_ERR("while adding child\n");
00190                         goto error;
00191                 }
00192                 if (remotetarget && remotetarget->s) {
00193                         memcpy(buf, remotetarget->s, remotetarget->len);
00194                         buf[remotetarget->len]= '\0';
00195                 }
00196                 xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
00197 
00198                 /* local tag*/  
00199                 local_node = xmlNewChild(dialog_node, NULL, BAD_CAST "local", NULL) ;
00200                 if( local_node ==NULL)
00201                 {
00202                         LM_ERR("while adding child\n");
00203                         goto error;
00204                 }
00205 
00206                 if (entity->len > MAX_URI_SIZE) {
00207                         LM_ERR("entity '%.*s' too long, maximum=%d\n", entity->len, entity->s, MAX_URI_SIZE);
00208                         return NULL;
00209                 }
00210         memcpy(buf, entity->s, entity->len);
00211                 buf[entity->len]= '\0';
00212 
00213                 tag_node = xmlNewChild(local_node, NULL, BAD_CAST "identity", BAD_CAST buf) ;
00214                 if( tag_node ==NULL)
00215                 {
00216                         LM_ERR("while adding child\n");
00217                         goto error;
00218                 }
00219                 tag_node = xmlNewChild(local_node, NULL, BAD_CAST "target", NULL) ;
00220                 if( tag_node ==NULL)
00221                 {
00222                         LM_ERR("while adding child\n");
00223                         goto error;
00224                 }
00225                 if (localtarget && localtarget->s) {
00226                         memcpy(buf, localtarget->s, localtarget->len);
00227                         buf[localtarget->len]= '\0';
00228                 }
00229                 xmlNewProp(tag_node, BAD_CAST "uri", BAD_CAST buf);
00230         }
00231 
00232         /* create the body */
00233         body = (str*)pkg_malloc(sizeof(str));
00234         if(body == NULL)
00235         {
00236                 LM_ERR("while allocating memory\n");
00237                 return NULL;
00238         }
00239         memset(body, 0, sizeof(str));
00240 
00241         xmlDocDumpFormatMemory(doc,(unsigned char**)(void*)&body->s,&body->len,1);
00242 
00243         LM_DBG("new_body:\n%.*s\n",body->len, body->s);
00244 
00245     /*free the document */
00246         xmlFreeDoc(doc);
00247     xmlCleanupParser();
00248 
00249         return body;
00250 
00251 error:
00252         if(body)
00253         {
00254                 if(body->s)
00255                         xmlFree(body->s);
00256                 pkg_free(body);
00257         }
00258         if(doc)
00259                 xmlFreeDoc(doc);
00260         return NULL;
00261 }       
00262 
00263 void dialog_publish(char *state, str* ruri, str *entity, str *peer, str *callid,
00264         unsigned int initiator, unsigned int lifetime, str *localtag, str *remotetag,
00265         str *localtarget, str *remotetarget, unsigned short do_pubruri_localcheck)
00266 {
00267         str* body= NULL;
00268         str uri= {NULL, 0};
00269         publ_info_t* publ= NULL;
00270         int size= 0;
00271         str content_type;
00272     struct sip_uri ruri_uri;
00273 
00274 
00275     if (parse_uri(ruri->s, ruri->len, &ruri_uri) < 0) {
00276                 LM_ERR("failed to parse the PUBLISH R-URI\n");
00277                 return;
00278         }
00279 
00280     if(do_pubruri_localcheck) {
00281 
00282                 /* send PUBLISH only if the receiver PUBLISH R-URI is local*/
00283                 if (!check_self(&(ruri_uri.host), 0, 0)) {
00284                         LM_DBG("do not send PUBLISH to external URI %.*s\n",ruri->len, ruri->s);
00285                         return;
00286                 }
00287 
00288     }
00289 
00290         content_type.s= "application/dialog-info+xml";
00291         content_type.len= 27;
00292 
00293         body= build_dialoginfo(state, entity, peer, callid, initiator, localtag, remotetag, localtarget, remotetarget);
00294         if(body == NULL || body->s == NULL)
00295                 goto error;
00296         
00297         LM_DBG("publish uri= %.*s\n", ruri->len, ruri->s);
00298         
00299         size= sizeof(publ_info_t) 
00300                         + sizeof(str)                   /* *pres_uri */
00301                         + ( ruri->len           /* pres_uri->s */
00302                           + callid->len + 16    /* id.s */
00303                           + content_type.len    /* content_type.s */
00304                         )*sizeof(char); 
00305         
00306         if(body)
00307                 size+= sizeof(str)+ body->len* sizeof(char);
00308 
00309         publ= (publ_info_t*)pkg_malloc(size);
00310         if(publ== NULL)
00311         {
00312                 LM_ERR("no more share memory\n");
00313                 goto error;
00314         }
00315         memset(publ, 0, size);
00316         size= sizeof(publ_info_t);
00317 
00318         publ->pres_uri= (str*)((char*)publ + size);
00319         size+= sizeof(str);
00320         publ->pres_uri->s= (char*)publ+ size;
00321         memcpy(publ->pres_uri->s, ruri->s, ruri->len);
00322         publ->pres_uri->len= ruri->len;
00323         size+= ruri->len;
00324 
00325         if(body)
00326         {
00327                 publ->body= (str*)( (char*)publ + size);
00328                 size+= sizeof(str);
00329 
00330                 publ->body->s= (char*)publ + size;
00331                 memcpy(publ->body->s, body->s, body->len);
00332                 publ->body->len= body->len;
00333                 size+= body->len;
00334         }
00335         publ->id.s= (char*)publ+ size;
00336         memcpy(publ->id.s, "DIALOG_PUBLISH.", 15);
00337         memcpy(publ->id.s+15, callid->s, callid->len);
00338         publ->id.len= 15+ callid->len;
00339         size+= publ->id.len;
00340 
00341         publ->content_type.s= (char*)publ+ size;
00342         memcpy(publ->content_type.s, content_type.s, content_type.len);
00343         publ->content_type.len= content_type.len;
00344         size+= content_type.len;
00345 
00346         publ->expires= lifetime;
00347         
00348         /* make UPDATE_TYPE, as if this "publish dialog" is not found 
00349            by pua it will fallback to INSERT_TYPE anyway */
00350         publ->flag|= UPDATE_TYPE;
00351 
00352         publ->source_flag|= DIALOG_PUBLISH;
00353         publ->event|= DIALOG_EVENT;
00354         publ->extra_headers= NULL;
00355         print_publ(publ);
00356         if(pua_send_publish(publ)< 0)
00357         {
00358                 LM_ERR("while sending publish\n");
00359         }       
00360 
00361 error:
00362 
00363         if(publ)
00364                 pkg_free(publ);
00365 
00366         if(body)
00367         {
00368                 if(body->s)
00369                         xmlFree(body->s);
00370                 pkg_free(body);
00371         }
00372         
00373         if(uri.s)
00374                 pkg_free(uri.s);
00375 
00376         return;
00377 }
00378 
00379 
00380 
00381 void dialog_publish_multi(char *state, struct str_list* ruris, str *entity, str *peer, str *callid,
00382         unsigned int initiator, unsigned int lifetime, str *localtag, str *remotetag,
00383         str *localtarget, str *remotetarget, unsigned short do_pubruri_localcheck) {
00384 
00385         while(ruris) {
00386                 LM_INFO("CALLING dialog_publish for URI %.*s\n",ruris->s.len, ruris->s.s);
00387                 dialog_publish(state,&(ruris->s),entity,peer,callid,initiator,lifetime,localtag,remotetag,localtarget,remotetarget,do_pubruri_localcheck);
00388                 ruris=ruris->next;
00389         }
00390 
00391 }