ul_publish.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
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 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <libxml/parser.h>
00037 #include <time.h>
00038 
00039 #include "../../parser/parse_expires.h"
00040 #include "../../parser/msg_parser.h"
00041 #include "../../str.h"
00042 #include "../../dset.h"
00043 #include "../usrloc/usrloc.h"
00044 #include "../usrloc/ul_callback.h"
00045 #include "../../modules/tm/tm_load.h"
00046 #include "../pua/pua.h"
00047 #include "pua_usrloc.h"
00048 
00049 #define BUF_LEN   256
00050 int pua_set_publish(struct sip_msg* msg , char* s1, char* s2)
00051 {
00052         LM_DBG("set send publish\n");
00053         pua_ul_publish= 1;
00054         if(pua_ul_bmask!=0)
00055                 setbflag(0, pua_ul_bflag);
00056         return 1;
00057 }
00058 
00059 int pua_unset_publish(struct sip_msg* msg, unsigned int flags, void* param)
00060 {
00061         pua_ul_publish= 0;
00062         if(pua_ul_bmask!=0)
00063                 resetbflag(0, pua_ul_bflag);
00064         return 1;
00065 }
00066 
00067         
00068 /* for debug purpose only */
00069 void print_publ(publ_info_t* p)
00070 {
00071         LM_DBG("publ:\n");
00072         LM_DBG("uri= %.*s\n", p->pres_uri->len, p->pres_uri->s);
00073         LM_DBG("id= %.*s\n", p->id.len, p->id.s);
00074         LM_DBG("expires= %d\n", p->expires);
00075 }       
00076 
00077 str* build_pidf(ucontact_t* c)
00078 {
00079         xmlDocPtr  doc = NULL; 
00080         xmlNodePtr root_node = NULL;
00081         xmlNodePtr tuple_node = NULL;
00082         xmlNodePtr status_node = NULL;
00083         xmlNodePtr basic_node = NULL;
00084         str *body= NULL;
00085         str pres_uri= {NULL, 0};
00086         char buf[BUF_LEN];
00087         char* at= NULL;
00088 
00089         if(c->expires< (int)time(NULL))
00090         {
00091                 LM_DBG("found expired \n\n");
00092                 return NULL;
00093         }
00094 
00095         pres_uri.s = buf;
00096         if(pres_prefix.s)
00097         {
00098                 memcpy(pres_uri.s, pres_prefix.s, pres_prefix.len);
00099                 pres_uri.len+= pres_prefix.len;
00100                 memcpy(pres_uri.s+ pres_uri.len, ":", 1);
00101                 pres_uri.len+= 1;
00102         }
00103         if(pres_uri.len + c->aor->len+ 1 > BUF_LEN)
00104         {
00105                 LM_ERR("buffer size overflown\n");
00106                 return NULL;
00107         }
00108 
00109         memcpy(pres_uri.s+ pres_uri.len, c->aor->s, c->aor->len);
00110         pres_uri.len+= c->aor->len;
00111 
00112         at = memchr(c->aor->s, '@', c->aor->len);
00113         if(!at)
00114         {
00115                 if(pres_uri.len + 2 + default_domain.len > BUF_LEN)
00116                 {
00117                         LM_ERR("buffer size overflown\n");
00118                         return NULL;
00119                 }
00120 
00121                 pres_uri.s[pres_uri.len++]= '@';
00122                 memcpy(pres_uri.s+ pres_uri.len, default_domain.s, default_domain.len);
00123                 pres_uri.len+= default_domain.len;              
00124         }
00125         pres_uri.s[pres_uri.len]= '\0';
00126 
00127         /* create the Publish body  */
00128         doc = xmlNewDoc(BAD_CAST "1.0");
00129         if(doc==0)
00130                 return NULL;
00131 
00132         root_node = xmlNewNode(NULL, BAD_CAST "presence");
00133         if(root_node==0)
00134                 goto error;
00135     
00136         xmlDocSetRootElement(doc, root_node);
00137 
00138         xmlNewProp(root_node, BAD_CAST "xmlns",
00139                         BAD_CAST "urn:ietf:params:xml:ns:pidf");
00140         xmlNewProp(root_node, BAD_CAST "xmlns:dm",
00141                         BAD_CAST "urn:ietf:params:xml:ns:pidf:data-model");
00142         xmlNewProp(root_node, BAD_CAST  "xmlns:rpid",
00143                         BAD_CAST "urn:ietf:params:xml:ns:pidf:rpid" );
00144         xmlNewProp(root_node, BAD_CAST "xmlns:c",
00145                         BAD_CAST "urn:ietf:params:xml:ns:pidf:cipid");
00146         xmlNewProp(root_node, BAD_CAST "entity", BAD_CAST pres_uri.s);
00147 
00148         tuple_node =xmlNewChild(root_node, NULL, BAD_CAST "tuple", NULL) ;
00149         if( tuple_node ==NULL)
00150         {
00151                 LM_ERR("while adding child\n");
00152                 goto error;
00153         }
00154         
00155         status_node = xmlNewChild(tuple_node, NULL, BAD_CAST "status", NULL) ;
00156         if( status_node ==NULL)
00157         {
00158                 LM_ERR("while adding child\n");
00159                 goto error;
00160         }
00161         
00162         basic_node = xmlNewChild(status_node, NULL, BAD_CAST "basic",
00163                 BAD_CAST "open") ;
00164         
00165         if( basic_node ==NULL)
00166         {
00167                 LM_ERR("while adding child\n");
00168                 goto error;
00169         }
00170         
00171         body = (str*)pkg_malloc(sizeof(str));
00172         if(body == NULL)
00173         {
00174                 LM_ERR("while allocating memory\n");
00175                 return NULL;
00176         }
00177         memset(body, 0, sizeof(str));
00178 
00179         xmlDocDumpFormatMemory(doc,(unsigned char**)(void*)&body->s,&body->len,1);
00180 
00181         LM_DBG("new_body:\n%.*s\n",body->len, body->s);
00182 
00183         /*free the document */
00184         xmlFreeDoc(doc);
00185         xmlCleanupParser();
00186 
00187         return body;
00188 
00189 error:
00190         if(body)
00191         {
00192                 if(body->s)
00193                         xmlFree(body->s);
00194                 pkg_free(body);
00195         }
00196         if(doc)
00197                 xmlFreeDoc(doc);
00198         return NULL;
00199 }       
00200 
00201 void ul_publish(ucontact_t* c, int type, void* param)
00202 {
00203         str* body= NULL;
00204         str uri= {NULL, 0};
00205         char* at= NULL;
00206         publ_info_t* publ= NULL;
00207         int size= 0;
00208         str content_type;
00209         int error;
00210 
00211         content_type.s= "application/pidf+xml";
00212         content_type.len= 20;
00213 
00214         if(pua_ul_publish==0 && pua_ul_bmask==0)
00215         {
00216                 LM_INFO("should not send ul publish\n");
00217                 return;
00218         }
00219         if(pua_ul_bmask!=0 && (c->cflags & pua_ul_bmask)==0)
00220         {
00221                 LM_INFO("not marked for publish\n");
00222                 return;
00223         }
00224 
00225         if(type & UL_CONTACT_DELETE) {
00226                 LM_DBG("\nDELETE type\n");
00227         } else {
00228                 if(type & UL_CONTACT_INSERT) {
00229                         LM_DBG("\nINSERT type\n");
00230                 } else {
00231                         if(type & UL_CONTACT_UPDATE) {
00232                                 LM_DBG("\nUPDATE type\n");
00233                         } else {
00234                                 if(type & UL_CONTACT_EXPIRE) {
00235                                         LM_DBG("\nEXPIRE type\n");
00236                                 }
00237                         }
00238                 }
00239         }
00240 
00241         if(type & UL_CONTACT_INSERT)
00242         {
00243                 body= build_pidf(c);
00244                 if(body == NULL || body->s == NULL)
00245                         goto error;
00246         }
00247         else
00248                 body = NULL;
00249         
00250         uri.s = (char*)pkg_malloc(sizeof(char)*(c->aor->len+default_domain.len+6));
00251         if(uri.s == NULL)
00252                 goto error;
00253 
00254         memcpy(uri.s, "sip:", 4);
00255         uri.len = 4;
00256         memcpy(uri.s+ uri.len, c->aor->s, c->aor->len);
00257         uri.len+= c->aor->len;
00258         at = memchr(c->aor->s, '@', c->aor->len);
00259         if(!at)
00260         {
00261                 uri.s[uri.len++]= '@';
00262                 memcpy(uri.s+ uri.len, default_domain.s, default_domain.len);
00263                 uri.len+= default_domain.len;           
00264         }
00265         LM_DBG("uri= %.*s\n", uri.len, uri.s);
00266         
00267         size= sizeof(publ_info_t)+ sizeof(str)+( uri.len 
00268                         +c->callid.len+ 12 + content_type.len)*sizeof(char); 
00269         
00270         if(body)
00271                 size+= sizeof(str)+ body->len* sizeof(char);
00272 
00273         publ= (publ_info_t*)pkg_malloc(size);
00274         if(publ== NULL)
00275         {
00276                 LM_ERR("no more share memory\n");
00277                 goto error;
00278         }
00279         memset(publ, 0, size);
00280         size= sizeof(publ_info_t);
00281 
00282         publ->pres_uri= (str*)((char*)publ + size);
00283         size+= sizeof(str);
00284         publ->pres_uri->s= (char*)publ+ size;
00285         memcpy(publ->pres_uri->s, uri.s, uri.len);
00286         publ->pres_uri->len= uri.len;
00287         size+= uri.len;
00288 
00289         if(body)
00290         {
00291                 publ->body= (str*)( (char*)publ + size);
00292                 size+= sizeof(str);
00293 
00294                 publ->body->s= (char*)publ + size;
00295                 memcpy(publ->body->s, body->s, body->len);
00296                 publ->body->len= body->len;
00297                 size+= body->len;
00298         }
00299         publ->id.s= (char*)publ+ size;
00300         memcpy(publ->id.s, "UL_PUBLISH.", 11);
00301         memcpy(publ->id.s+11, c->callid.s, c->callid.len);
00302         publ->id.len= 11+ c->callid.len;
00303         size+= publ->id.len;
00304 
00305         publ->content_type.s= (char*)publ+ size;
00306         memcpy(publ->content_type.s, content_type.s, content_type.len);
00307         publ->content_type.len= content_type.len;
00308         size+= content_type.len;
00309 
00310         if(type & UL_CONTACT_EXPIRE || type & UL_CONTACT_DELETE)
00311                 publ->expires= 0;
00312         else
00313                 publ->expires= c->expires - (int)time(NULL);
00314         
00315         if(type & UL_CONTACT_INSERT)
00316                 publ->flag|= INSERT_TYPE;
00317         else
00318                 publ->flag|= UPDATE_TYPE;
00319 
00320         publ->source_flag|= UL_PUBLISH;
00321         publ->event|= PRESENCE_EVENT;
00322         publ->extra_headers= NULL;
00323         print_publ(publ);
00324         if((error=pua_send_publish(publ))< 0)
00325         {
00326                 LM_ERR("while sending publish\n");
00327                 if(type & UL_CONTACT_UPDATE && error == ERR_PUBLISH_NO_BODY) {
00328                         /* This error can occur if Kamailio was restarted/stopped and for any reason couldn't store a pua
00329                          * entry in 'pua' DB table. It can also occur if 'pua' table is cleaned externally while Kamailio
00330                          * is stopped so cannot retrieve these entries from DB when restarting.
00331                          * In these cases, when a refresh registration for that user creates an UPDATE action in pua_usrloc,
00332                          * pua 'ul_publish()' would fail since the appropiate entry doesn't exist in pua hast table ("New 
00333                          * PUBLISH and no body found - invalid request").
00334                          * This code solves this problem by invoking an INSERT action if an UPDATE action failed due to the 
00335                          * above error. It will however generate a new presentity entry in the presence server (until the
00336                          * previous one expires), but this is a minor issue. */
00337                         LM_ERR("UPDATE action generated a PUBLISH without body -> invoking INSERT action\n");
00338                         ul_publish(c, UL_CONTACT_INSERT, param);
00339                         return;
00340                 }
00341         }
00342 
00343         pua_ul_publish= 0;
00344 
00345 error:
00346 
00347         if(publ)
00348                 pkg_free(publ);
00349 
00350         if(body)
00351         {
00352                 if(body->s)
00353                         xmlFree(body->s);
00354                 pkg_free(body);
00355         }
00356         
00357         if(uri.s)
00358                 pkg_free(uri.s);
00359         pua_ul_publish= 0;
00360 
00361         return;
00362 
00363 }
00364 
00365