You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/pua/send_subscribe.c

1238 lines
31 KiB

/*
* $Id$
*
* pua module - presence user agent module
*
* Copyright (C) 2006 Voice Sistem S.R.L.
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio 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 2 of the License, or
* (at your option) any later version
*
* Kamailio 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libxml/parser.h>
#include "../../mem/mem.h"
#include "../../dprint.h"
#include "../../ut.h"
#include "../../modules/tm/tm_load.h"
#include "../../modules/tm/dlg.h"
#include "../../parser/msg_parser.h"
#include "../../parser/contact/parse_contact.h"
#include "../../parser/parse_from.h"
#include "../../parser/parse_expires.h"
#include "../presence/hash.h"
#include "../../hashes.h"
#include "hash.h"
#include "pua.h"
#include "send_subscribe.h"
#include "pua_callback.h"
#include "event_list.h"
#include "pua_db.h"
#include "../presence/subscribe.h"
void print_subs(subs_info_t* subs)
{
LM_DBG("pres_uri= %.*s - len: %d\n",
subs->pres_uri->len, subs->pres_uri->s, subs->pres_uri->len );
LM_DBG("watcher_uri= %.*s - len: %d\n",
subs->watcher_uri->len, subs->watcher_uri->s,
subs->watcher_uri->len);
}
str* subs_build_hdr(str* contact, int expires, int event, str* extra_headers)
{
str* str_hdr= NULL;
static char buf[3000];
char* subs_expires= NULL;
int len= 1;
pua_event_t* ev;
str_hdr= (str*)pkg_malloc(sizeof(str));
if(str_hdr== NULL)
{
LM_ERR("no more memory\n");
return NULL;
}
memset(str_hdr, 0, sizeof(str));
str_hdr->s= buf;
ev= get_event(event);
if(ev== NULL)
{
LM_ERR("getting event from list\n");
goto error;
}
memcpy(str_hdr->s ,"Max-Forwards: ", 14);
str_hdr->len = 14;
str_hdr->len+= sprintf(str_hdr->s+ str_hdr->len,"%d", MAX_FORWARD);
memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
str_hdr->len += CRLF_LEN;
memcpy(str_hdr->s+ str_hdr->len ,"Event: ", 7);
str_hdr->len+= 7;
memcpy(str_hdr->s+ str_hdr->len, ev->name.s, ev->name.len);
str_hdr->len+= ev->name.len;
memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
str_hdr->len += CRLF_LEN;
memcpy(str_hdr->s+ str_hdr->len ,"Contact: <", 10);
str_hdr->len += 10;
memcpy(str_hdr->s +str_hdr->len, contact->s,
contact->len);
str_hdr->len+= contact->len;
memcpy(str_hdr->s+ str_hdr->len, ">", 1);
str_hdr->len+= 1;
memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
str_hdr->len += CRLF_LEN;
memcpy(str_hdr->s+ str_hdr->len ,"Expires: ", 9);
str_hdr->len += 9;
if( expires<= min_expires)
subs_expires= int2str(min_expires, &len);
else
subs_expires= int2str(expires+ 10, &len);
if(subs_expires == NULL || len == 0)
{
LM_ERR("while converting int to str\n");
pkg_free(str_hdr);
return NULL;
}
memcpy(str_hdr->s+str_hdr->len, subs_expires, len);
str_hdr->len += len;
memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
str_hdr->len += CRLF_LEN;
if(extra_headers && extra_headers->len)
{
memcpy(str_hdr->s+str_hdr->len, extra_headers->s, extra_headers->len);
str_hdr->len += extra_headers->len;
}
str_hdr->s[str_hdr->len]= '\0';
return str_hdr;
error:
if(str_hdr)
pkg_free(str_hdr);
return NULL;
}
dlg_t* pua_build_dlg_t(ua_pres_t* presentity)
{
dlg_t* td =NULL;
int size;
size= sizeof(dlg_t)+ presentity->call_id.len+ presentity->to_tag.len+
presentity->from_tag.len+ presentity->watcher_uri->len+
presentity->pres_uri->len+ presentity->remote_contact.len;
td = (dlg_t*)pkg_malloc(size);
if(td == NULL)
{
LM_ERR("No memory left\n");
return NULL;
}
memset(td, 0, size);
size= sizeof(dlg_t);
td->id.call_id.s = (char*)td+ size;
memcpy(td->id.call_id.s, presentity->call_id.s, presentity->call_id.len);
td->id.call_id.len= presentity->call_id.len;
size+= presentity->call_id.len;
td->id.rem_tag.s = (char*)td+ size;
memcpy(td->id.rem_tag.s, presentity->to_tag.s, presentity->to_tag.len);
td->id.rem_tag.len = presentity->to_tag.len;
size+= presentity->to_tag.len;
td->id.loc_tag.s = (char*)td+ size;
memcpy(td->id.loc_tag.s, presentity->from_tag.s, presentity->from_tag.len);
td->id.loc_tag.len =presentity->from_tag.len;
size+= presentity->from_tag.len;
td->loc_uri.s = (char*)td+ size;
memcpy(td->loc_uri.s, presentity->watcher_uri->s,
presentity->watcher_uri->len) ;
td->loc_uri.len = presentity->watcher_uri->len;
size+= td->loc_uri.len;
td->rem_uri.s = (char*)td+ size;
memcpy(td->rem_uri.s, presentity->pres_uri->s, presentity->pres_uri->len) ;
td->rem_uri.len = presentity->pres_uri->len;
size+= td->rem_uri.len;
td->rem_target.s = (char*)td+ size;
memcpy(td->rem_target.s, presentity->remote_contact.s,
presentity->remote_contact.len) ;
td->rem_target.len = presentity->remote_contact.len;
size+= td->rem_target.len;
if(presentity->record_route.s && presentity->record_route.len)
{
if(parse_rr_body(presentity->record_route.s, presentity->record_route.len,
&td->route_set)< 0)
{
LM_ERR("ERROR in function parse_rr_body\n");
pkg_free(td);
return NULL;
}
}
td->loc_seq.value = presentity->cseq;
td->loc_seq.is_set = 1;
td->state= DLG_CONFIRMED ;
LM_DBG("size = %d\n", size);
return td;
}
/**
* free the field in dlg_t as filled/allocated by this module
*/
static int pua_free_tm_dlg(dlg_t *td)
{
if(td)
{
if(td->route_set)
free_rr(&td->route_set);
pkg_free(td);
}
return 0;
}
static void find_and_delete_dialog(ua_pres_t *dialog, int hash_code)
{
ua_pres_t *presentity;
if (dbmode == PUA_DB_ONLY)
{
delete_dialog_puadb(dialog);
}
else
{
lock_get(&HashT->p_records[hash_code].lock);
presentity= get_dialog(dialog, hash_code);
if (presentity == NULL)
{
presentity = get_temporary_dialog(dialog, hash_code);
if(presentity== NULL)
{
LM_ERR("no record found\n");
lock_release(&HashT->p_records[hash_code].lock);
return;
}
}
delete_htable(presentity, hash_code);
lock_release(&HashT->p_records[hash_code].lock);
}
}
static void find_and_update_dialog(ua_pres_t *dialog, int hash_code, int lexpire, str *contact)
{
ua_pres_t *presentity;
if (dbmode == PUA_DB_ONLY)
{
update_dialog_puadb(dialog, lexpire, contact);
}
else
{
lock_get(&HashT->p_records[hash_code].lock);
presentity= get_dialog(dialog, hash_code);
if (presentity == NULL)
{
LM_ERR("no record found\n");
lock_release(&HashT->p_records[hash_code].lock);
return;
}
update_htable(presentity, dialog->desired_expires, lexpire, NULL, hash_code, contact);
lock_release(&HashT->p_records[hash_code].lock);
}
}
void subs_cback_func(struct cell *t, int cb_type, struct tmcb_params *ps)
{
struct sip_msg* msg= NULL;
int lexpire= 0;
unsigned int cseq;
ua_pres_t* presentity= NULL, *hentity= NULL;
struct to_body *pto = NULL, TO = {0}, *pfrom = NULL;
int size= 0;
unsigned int hash_code;
int flag ;
str record_route= {0, 0};
int rt;
str contact;
int initial_request = 0;
int end_transaction = 1;
if( ps->param== NULL || *ps->param== NULL )
{
LM_ERR("null callback parameter\n");
return;
}
if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction)
{
if (pua_dbf.start_transaction(pua_db, DB_LOCKING_WRITE) < 0)
{
LM_ERR("in start_transaction\n");
goto error;
}
}
LM_DBG("completed with status %d\n",ps->code) ;
hentity= (ua_pres_t*)(*ps->param);
hash_code= core_hash(hentity->pres_uri,hentity->watcher_uri,
HASH_SIZE);
flag= hentity->flag;
if(hentity->flag & XMPP_INITIAL_SUBS)
hentity->flag= XMPP_SUBSCRIBE;
/* get dialog information from reply message: callid, to_tag, from_tag */
msg= ps->rpl;
if(msg == NULL)
{
LM_ERR("no reply message found\n ");
goto error;
}
if(msg== FAKED_REPLY)
{
struct hdr_field *callid = NULL, *from = NULL;
struct to_body FROM = {0};
callid = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
if (callid == NULL)
{
LM_ERR("Out of memory\n");
goto faked_error;
}
memset(callid, 0, sizeof(struct hdr_field));
get_hdr_field(t->callid.s, t->callid.s + t->callid.len, callid);
hentity->call_id = callid->body;
from = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field));
if (from == NULL)
{
LM_ERR("Out of memory\n");
goto faked_error;
}
memset(from, 0, sizeof(struct hdr_field));
get_hdr_field(t->from.s, t->from.s + t->from.len, from);
parse_to(from->body.s, from->body.s + from->body.len + 1, &FROM);
if(FROM.uri.len <= 0)
{
LM_ERR("'From' header NOT parsed\n");
goto faked_error;
}
hentity->call_id = callid->body;
hentity->from_tag = (&FROM)->tag_value;
hentity->to_tag.s = NULL;
hentity->to_tag.len = 0;
find_and_delete_dialog(hentity, hash_code);
faked_error:
if (callid) pkg_free(callid);
free_to_params(&FROM);
if (from) pkg_free(from);
goto done;
}
if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
{
LM_ERR("when parsing headers\n");
goto error;
}
if(ps->rpl->expires && msg->expires->body.len > 0)
{
if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
{
LM_ERR("cannot parse Expires header\n");
goto error;
}
lexpire = ((exp_body_t*)msg->expires->parsed)->val;
LM_DBG("lexpire= %d\n", lexpire);
}
/*if initial request */
if(hentity->call_id.s== NULL)
{
initial_request = 1;
if( msg->callid==NULL || msg->callid->body.s==NULL)
{
LM_ERR("cannot parse callid header\n");
goto error;
}
if (!msg->from || !msg->from->body.s)
{
LM_ERR("cannot find 'from' header!\n");
goto error;
}
if (msg->from->parsed == NULL)
{
if ( parse_from_header( msg )<0 )
{
LM_ERR("cannot parse From header\n");
goto error;
}
}
pfrom = (struct to_body*)msg->from->parsed;
if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
{
LM_ERR("no from tag value present\n");
goto error;
}
hentity->call_id= msg->callid->body;
hentity->from_tag= pfrom->tag_value;
if(ps->code >= 300 || lexpire == 0)
{
hentity->to_tag.s = NULL;
hentity->to_tag.len = 0;
find_and_delete_dialog(hentity, hash_code);
goto done;
}
if( msg->to==NULL || msg->to->body.s==NULL)
{
LM_ERR("cannot parse TO header\n");
goto error;
}
if(msg->to->parsed != NULL)
{
pto = (struct to_body*)msg->to->parsed;
LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
}
else
{
parse_to(msg->to->body.s,msg->to->body.s +
msg->to->body.len + 1, &TO);
if(TO.uri.len <= 0)
{
LM_ERR("'To' header NOT parsed\n");
goto error;
}
pto = &TO;
}
if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
{
LM_ERR("no to tag value present\n");
goto error;
}
hentity->to_tag= pto->tag_value;
}
if(ps->code >= 300 )
{ /* if an error code and a stored dialog delete it and try to send
a subscription with type= INSERT_TYPE, else return*/
subs_info_t subs;
hentity->to_tag.s = NULL;
hentity->to_tag.len = 0;
find_and_delete_dialog(hentity, hash_code);
if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction)
{
if (pua_dbf.end_transaction(pua_db) < 0)
{
LM_ERR("in end_transaction\n");
goto error;
}
}
end_transaction = 0;
/* Redirect if the response 3XX */
memset(&subs, 0, sizeof(subs_info_t));
subs.pres_uri= hentity->pres_uri;
subs.watcher_uri= hentity->watcher_uri;
subs.contact= &hentity->contact;
if(hentity->remote_contact.s)
subs.remote_target= &hentity->remote_contact;
if(hentity->desired_expires== 0)
subs.expires= -1;
else
if(hentity->desired_expires< (int)time(NULL))
subs.expires= 0;
else
subs.expires= hentity->desired_expires- (int)time(NULL)+ 3;
subs.flag= INSERT_TYPE;
subs.source_flag= flag;
subs.event= hentity->event;
subs.id= hentity->id;
subs.outbound_proxy= hentity->outbound_proxy;
subs.extra_headers= hentity->extra_headers;
subs.cb_param= hentity->cb_param;
if(send_subscribe(&subs)< 0)
{
LM_ERR("when trying to send SUBSCRIBE\n");
goto error;
}
goto done;
}
if(lexpire== 0 )
{
LM_DBG("lexpire= 0 Delete from hash table");
find_and_delete_dialog(hentity, hash_code);
goto done;
}
/* extract the contact */
if(msg->contact== NULL || msg->contact->body.s== NULL)
{
LM_ERR("no contact header found");
goto error;
}
if( parse_contact(msg->contact) <0 )
{
LM_ERR(" cannot parse contact header\n");
goto error;
}
if(msg->contact->parsed == NULL)
{
LM_ERR("cannot parse contact header\n");
goto error;
}
contact = ((contact_body_t* )msg->contact->parsed)->contacts->uri;
if( msg->cseq==NULL || msg->cseq->body.s==NULL)
{
LM_ERR("cannot parse cseq header\n");
goto error;
}
if( str2int( &(get_cseq(msg)->number), &cseq)< 0)
{
LM_ERR("while converting str to int\n");
goto error;
}
if(initial_request == 0)
{
hentity->cseq = cseq;
find_and_update_dialog(hentity, hash_code, lexpire, &contact);
goto done;
}
/*process record route and add it to a string*/
if (msg->record_route!=NULL)
{
rt = print_rr_body(msg->record_route, &record_route, 1, 0);
if(rt != 0)
{
LM_ERR("parsing record route [%d]\n", rt);
record_route.s=NULL;
record_route.len=0;
}
}
size= sizeof(ua_pres_t)+ 2*sizeof(str)+( pto->uri.len+
pfrom->uri.len+ pto->tag_value.len+ pfrom->tag_value.len
+msg->callid->body.len+ record_route.len+ hentity->contact.len+
hentity->id.len )*sizeof(char);
if(hentity->extra_headers)
size+= sizeof(str)+ hentity->extra_headers->len*sizeof(char);
presentity= (ua_pres_t*)shm_malloc(size);
if(presentity== NULL)
{
LM_ERR("no more share memory\n");
goto error;
}
memset(presentity, 0, size);
size= sizeof(ua_pres_t);
presentity->pres_uri= (str*)( (char*)presentity+ size);
size+= sizeof(str);
presentity->pres_uri->s= (char*)presentity+ size;
memcpy(presentity->pres_uri->s, pto->uri.s, pto->uri.len);
presentity->pres_uri->len= pto->uri.len;
size+= pto->uri.len;
presentity->watcher_uri= (str*)( (char*)presentity+ size);
size+= sizeof(str);
presentity->watcher_uri->s= (char*)presentity+ size;
memcpy(presentity->watcher_uri->s, pfrom->uri.s, pfrom->uri.len);
presentity->watcher_uri->len= pfrom->uri.len;
size+= pfrom->uri.len;
presentity->call_id.s= (char*)presentity + size;
memcpy(presentity->call_id.s,msg->callid->body.s,
msg->callid->body.len);
presentity->call_id.len= msg->callid->body.len;
size+= presentity->call_id.len;
presentity->to_tag.s= (char*)presentity + size;
memcpy(presentity->to_tag.s,pto->tag_value.s,
pto->tag_value.len);
presentity->to_tag.len= pto->tag_value.len;
size+= pto->tag_value.len;
presentity->from_tag.s= (char*)presentity + size;
memcpy(presentity->from_tag.s,pfrom->tag_value.s,
pfrom->tag_value.len);
presentity->from_tag.len= pfrom->tag_value.len;
size+= pfrom->tag_value.len;
if(record_route.len && record_route.s)
{
presentity->record_route.s= (char*)presentity + size;
memcpy(presentity->record_route.s, record_route.s, record_route.len);
presentity->record_route.len= record_route.len;
size+= record_route.len;
pkg_free(record_route.s);
record_route.s = NULL;
}
presentity->contact.s= (char*)presentity + size;
memcpy(presentity->contact.s, hentity->contact.s, hentity->contact.len);
presentity->contact.len= hentity->contact.len;
size+= hentity->contact.len;
if(hentity->id.s)
{
presentity->id.s=(char*)presentity+ size;
memcpy(presentity->id.s, hentity->id.s,
hentity->id.len);
presentity->id.len= hentity->id.len;
size+= presentity->id.len;
}
if(hentity->extra_headers)
{
presentity->extra_headers= (str*)((char*)presentity+ size);
size+= sizeof(str);
presentity->extra_headers->s=(char*)presentity+ size;
memcpy(presentity->extra_headers->s, hentity->extra_headers->s,
hentity->extra_headers->len);
presentity->extra_headers->len= hentity->extra_headers->len;
size+= hentity->extra_headers->len;
}
/* write the remote contact filed */
presentity->remote_contact.s= (char*)shm_malloc(contact.len* sizeof(char));
if(presentity->remote_contact.s==NULL)
{
ERR_MEM(SHARE_MEM);
}
memcpy(presentity->remote_contact.s, contact.s, contact.len);
presentity->remote_contact.len= contact.len;
presentity->event|= hentity->event;
presentity->flag= hentity->flag;
presentity->etag.s= NULL;
presentity->cseq= cseq;
presentity->desired_expires= hentity->desired_expires;
presentity->expires= lexpire+ (int)time(NULL);
if(BLA_SUBSCRIBE & presentity->flag)
{
LM_DBG("BLA_SUBSCRIBE FLAG inserted\n");
}
LM_DBG("record for subscribe from %.*s to %.*s inserted in datatbase\n",
presentity->watcher_uri->len, presentity->watcher_uri->s,
presentity->pres_uri->len, presentity->pres_uri->s);
if (dbmode==PUA_DB_ONLY)
{
if (pua_dbf.end_transaction)
{
if (pua_dbf.end_transaction(pua_db) < 0)
{
LM_ERR("in end_transaction\n");
goto error;
}
}
if (pua_dbf.start_transaction)
{
if (pua_dbf.start_transaction(pua_db, DB_LOCKING_WRITE) < 0)
{
LM_ERR("in start_transaction\n");
goto error;
}
}
if (convert_temporary_dialog_puadb(presentity) < 0)
{
LM_ERR("Could not convert temporary dialog into a dialog\n");
goto error;
}
}
else
{
if (convert_temporary_dialog(presentity) < 0)
{
LM_ERR("Could not convert temporary dialog into a dialog\n");
goto error;
}
}
done:
if(hentity->ua_flag == REQ_OTHER)
{
hentity->flag= flag;
run_pua_callbacks( hentity, msg);
}
if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction && end_transaction)
{
if (pua_dbf.end_transaction(pua_db) < 0)
{
LM_ERR("in end_transaction\n");
goto error;
}
}
goto end;
error:
if (presentity)
{
if (presentity->remote_contact.s) shm_free(presentity->remote_contact.s);
shm_free(presentity);
}
if(record_route.s)
pkg_free(record_route.s);
if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction)
{
if (pua_dbf.abort_transaction(pua_db) < 0)
LM_ERR("in abort_transaction\n");
}
end:
if(hentity)
{
shm_free(hentity);
hentity= NULL;
}
free_to_params(&TO);
return;
}
ua_pres_t* subscribe_cbparam(subs_info_t* subs, int ua_flag)
{
ua_pres_t* hentity= NULL;
int size;
size= sizeof(ua_pres_t)+ 2*sizeof(str)+(subs->pres_uri->len+
subs->watcher_uri->len+ subs->contact->len+ subs->id.len+ 1)*
sizeof(char);
if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s )
size+= sizeof(str)+ subs->outbound_proxy->len* sizeof(char);
if(subs->extra_headers && subs->extra_headers->s)
size+= sizeof(str)+ subs->extra_headers->len* sizeof(char);
hentity= (ua_pres_t*)shm_malloc(size);
if(hentity== NULL)
{
LM_ERR("No more share memory\n");
return NULL;
}
memset(hentity, 0, size);
size= sizeof(ua_pres_t);
hentity->pres_uri = (str*)((char*)hentity + size);
size+= sizeof(str);
hentity->pres_uri->s = (char*)hentity+ size;
memcpy(hentity->pres_uri->s, subs->pres_uri->s ,
subs->pres_uri->len ) ;
hentity->pres_uri->len= subs->pres_uri->len;
size+= subs->pres_uri->len;
hentity->watcher_uri = (str*)((char*)hentity + size);
size+= sizeof(str);
hentity->watcher_uri->s = (char*)hentity+ size;
memcpy(hentity->watcher_uri->s, subs->watcher_uri->s ,
subs->watcher_uri->len ) ;
hentity->watcher_uri->len= subs->watcher_uri->len;
size+= subs->watcher_uri->len;
hentity->contact.s = (char*)hentity+ size;
memcpy(hentity->contact.s, subs->contact->s ,
subs->contact->len );
hentity->contact.len= subs->contact->len;
size+= subs->contact->len;
if(subs->outbound_proxy)
{
hentity->outbound_proxy= (str*)((char*)hentity+ size);
size+= sizeof(str);
hentity->outbound_proxy->s= (char*)hentity+ size;
memcpy(hentity->outbound_proxy->s, subs->outbound_proxy->s, subs->outbound_proxy->len);
hentity->outbound_proxy->len= subs->outbound_proxy->len;
size+= subs->outbound_proxy->len;
}
if(subs->expires< 0)
hentity->desired_expires= 0;
else
hentity->desired_expires=subs->expires+ (int)time(NULL);
if(subs->id.s)
{
CONT_COPY(hentity, hentity->id, subs->id)
}
if(subs->extra_headers)
{
hentity->extra_headers= (str*)((char*)hentity+ size);
size+= sizeof(str);
hentity->extra_headers->s= (char*)hentity+ size;
memcpy(hentity->extra_headers->s, subs->extra_headers->s,
subs->extra_headers->len);
hentity->extra_headers->len= subs->extra_headers->len;
size+= subs->extra_headers->len;
}
hentity->flag= subs->source_flag;
hentity->event= subs->event;
hentity->ua_flag= hentity->ua_flag;
hentity->cb_param= subs->cb_param;
return hentity;
}
ua_pres_t* subs_cbparam_indlg(ua_pres_t* subs, int expires, int ua_flag)
{
ua_pres_t* hentity= NULL;
int size;
size= sizeof(ua_pres_t)+ 2*sizeof(str)+subs->pres_uri->len+
subs->watcher_uri->len+ subs->contact.len+ subs->id.len+
subs->to_tag.len+ subs->call_id.len+ subs->from_tag.len+ 1;
if(subs->outbound_proxy && subs->outbound_proxy->len && subs->outbound_proxy->s )
size+= sizeof(str)+ subs->outbound_proxy->len;
if(subs->extra_headers && subs->extra_headers->s)
size+= sizeof(str)+ subs->extra_headers->len;
if(subs->remote_contact.s)
size+= subs->remote_contact.len;
hentity= (ua_pres_t*)shm_malloc(size);
if(hentity== NULL)
{
LM_ERR("No more share memory\n");
return NULL;
}
memset(hentity, 0, size);
size= sizeof(ua_pres_t);
hentity->pres_uri = (str*)((char*)hentity + size);
size+= sizeof(str);
hentity->pres_uri->s = (char*)hentity+ size;
memcpy(hentity->pres_uri->s, subs->pres_uri->s ,
subs->pres_uri->len ) ;
hentity->pres_uri->len= subs->pres_uri->len;
size+= subs->pres_uri->len;
hentity->watcher_uri = (str*)((char*)hentity + size);
size+= sizeof(str);
hentity->watcher_uri->s = (char*)hentity+ size;
memcpy(hentity->watcher_uri->s, subs->watcher_uri->s ,
subs->watcher_uri->len ) ;
hentity->watcher_uri->len= subs->watcher_uri->len;
size+= subs->watcher_uri->len;
CONT_COPY(hentity, hentity->contact, subs->contact)
if(subs->outbound_proxy)
{
hentity->outbound_proxy= (str*)((char*)hentity+ size);
size+= sizeof(str);
hentity->outbound_proxy->s= (char*)hentity+ size;
memcpy(hentity->outbound_proxy->s, subs->outbound_proxy->s, subs->outbound_proxy->len);
hentity->outbound_proxy->len= subs->outbound_proxy->len;
size+= subs->outbound_proxy->len;
}
if(subs->id.s)
{
CONT_COPY(hentity, hentity->id, subs->id)
}
if(subs->remote_contact.s)
{
CONT_COPY(hentity, hentity->remote_contact, subs->remote_contact)
}
if(subs->extra_headers)
{
hentity->extra_headers= (str*)((char*)hentity+ size);
size+= sizeof(str);
hentity->extra_headers->s= (char*)hentity+ size;
memcpy(hentity->extra_headers->s, subs->extra_headers->s,
subs->extra_headers->len);
hentity->extra_headers->len= subs->extra_headers->len;
size+= subs->extra_headers->len;
}
/* copy dialog information */
CONT_COPY(hentity, hentity->to_tag, subs->to_tag)
CONT_COPY(hentity, hentity->from_tag, subs->from_tag)
CONT_COPY(hentity, hentity->call_id, subs->call_id)
if(expires< 0)
hentity->desired_expires= 0;
else
hentity->desired_expires=expires+ (int)time(NULL);
hentity->flag= subs->flag;
hentity->event= subs->event;
hentity->ua_flag= hentity->ua_flag;
hentity->cb_param= subs->cb_param;
return hentity;
}
/**
*
*/
int send_subscribe(subs_info_t* subs)
{
ua_pres_t* presentity= NULL;
str met= {"SUBSCRIBE", 9};
str* str_hdr= NULL;
int ret= -1;
unsigned int hash_code=0;
ua_pres_t* hentity= NULL;
int expires;
int flag;
int result;
uac_req_t uac_r;
db1_res_t *res=NULL;
ua_pres_t dbpres;
str pres_uri={0,0}, watcher_uri={0,0}, extra_headers={0,0};
dlg_t* td= NULL;
memset(&dbpres, 0, sizeof(dbpres));
dbpres.pres_uri = &pres_uri;
dbpres.watcher_uri = &watcher_uri;
dbpres.extra_headers = &extra_headers;
print_subs(subs);
flag= subs->source_flag;
if(subs->source_flag & XMPP_INITIAL_SUBS)
subs->source_flag= XMPP_SUBSCRIBE;
if(subs->expires< 0)
expires= 3600;
else
expires= subs->expires;
str_hdr= subs_build_hdr(subs->contact, expires, subs->event,
subs->extra_headers);
if(str_hdr== NULL || str_hdr->s== NULL)
{
LM_ERR("while building extra headers\n");
return -1;
}
if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction)
{
if (pua_dbf.start_transaction(pua_db, DB_LOCKING_WRITE) < 0)
{
LM_ERR("in start_transaction\n");
goto error;
}
}
/* generation of hash and getting lock moved from here to further down */
if (dbmode==PUA_DB_ONLY)
{
presentity = get_dialog_puadb(subs->id, subs->pres_uri, &dbpres, &res);
}
else
{
ua_pres_t pres;
memset(&pres, 0, sizeof(ua_pres_t));
pres.pres_uri = subs->pres_uri;
pres.watcher_uri = subs->watcher_uri;
pres.flag = subs->source_flag;
pres.id = subs->id;
pres.event = subs->event;
if (subs->remote_target)
pres.remote_contact = *subs->remote_target;
hash_code=core_hash(subs->pres_uri, subs->watcher_uri, HASH_SIZE);
lock_get(&HashT->p_records[hash_code].lock);
presentity= search_htable(&pres, hash_code);
}
/* if flag == INSERT_TYPE insert no matter what the search result is */
if(subs->flag & INSERT_TYPE)
{
LM_DBG("A subscription request with insert type\n");
goto insert;
}
if(presentity== NULL )
{
int size;
insert:
if (subs->expires == 0)
/* Don't create a new dialog when expires == 0 */
goto done;
if(subs->flag & UPDATE_TYPE)
{
LM_DBG("request for a subscription with update type"
" and no record found\n");
subs->flag= INSERT_TYPE;
}
hentity= subscribe_cbparam(subs, REQ_OTHER);
if(hentity== NULL)
{
LM_ERR("while building callback"
" param\n");
goto error;
}
hentity->flag= flag;
set_uac_req(&uac_r, &met, str_hdr, 0, 0, TMCB_LOCAL_COMPLETED,
subs_cback_func, (void*)hentity);
result= tmb.t_request_outside
(&uac_r, /* Type of the message */
subs->remote_target?subs->remote_target:subs->pres_uri,/* Request-URI*/
subs->pres_uri, /* To */
subs->watcher_uri, /* From */
subs->outbound_proxy /* Outbound_proxy */
);
if(result< 0)
{
LM_ERR("while sending request with t_request\n");
if (uac_r.dialog != NULL)
{
uac_r.dialog->rem_target.s = 0;
uac_r.dialog->dst_uri.s = 0;
tmb.free_dlg(uac_r.dialog);
uac_r.dialog = 0;
}
shm_free(hentity);
/* Although this is an error must not return -1 as the
calling function must continue processing. */
ret = 0;
goto error;
}
/* Now create a temporary hash table entry.
This is needed to deal with the race-hazard when NOTIFYs
arrive before the 2xx response to the SUBSCRIBE. */
size = sizeof(ua_pres_t)+ 2 * sizeof(str) + (
subs->pres_uri->len +
subs->watcher_uri->len +
uac_r.dialog->id.loc_tag.len +
uac_r.dialog->id.call_id.len +
subs->id.len) * sizeof(char);
presentity= (ua_pres_t*)shm_malloc(size);
if(presentity== NULL)
{
LM_ERR("no more share memory\n");
goto error;
}
memset(presentity, 0, size);
size= sizeof(ua_pres_t);
presentity->pres_uri = (str *) ((char *) presentity + size);
size += sizeof(str);
presentity->pres_uri->s= (char *) presentity + size;
memcpy(presentity->pres_uri->s, subs->pres_uri->s, subs->pres_uri->len);
presentity->pres_uri->len= subs->pres_uri->len;
size+= subs->pres_uri->len;
presentity->watcher_uri= (str *) ((char *) presentity + size);
size += sizeof(str);
presentity->watcher_uri->s= (char *) presentity + size;
memcpy(presentity->watcher_uri->s, subs->watcher_uri->s, subs->watcher_uri->len);
presentity->watcher_uri->len = subs->watcher_uri->len;
size += subs->watcher_uri->len;
presentity->call_id.s = (char *) presentity + size;
memcpy(presentity->call_id.s, uac_r.dialog->id.call_id.s, uac_r.dialog->id.call_id.len);
presentity->call_id.len = uac_r.dialog->id.call_id.len;
size += uac_r.dialog->id.call_id.len;
presentity->from_tag.s = (char *) presentity + size;
memcpy(presentity->from_tag.s, uac_r.dialog->id.loc_tag.s, uac_r.dialog->id.loc_tag.len);
presentity->from_tag.len= uac_r.dialog->id.loc_tag.len;
size += uac_r.dialog->id.loc_tag.len;
presentity->id.s = (char *) presentity+ size;
memcpy(presentity->id.s, subs->id.s, subs->id.len);
presentity->id.len = subs->id.len;
size += subs->id.len;
presentity->event = subs->event;
presentity->flag = subs->source_flag;
presentity->cseq = uac_r.dialog->loc_seq.value;
/* Set the temporary record expiry for 2 * 64T1 seconds from now */
presentity->expires= (int)time(NULL) + 64;
presentity->desired_expires= presentity->expires;
if (dbmode==PUA_DB_ONLY)
{
insert_dialog_puadb(presentity);
shm_free(presentity);
}
else
{
insert_htable(presentity, hash_code);
lock_release(&HashT->p_records[hash_code].lock);
}
uac_r.dialog->rem_target.s = 0;
uac_r.dialog->dst_uri.s = 0;
tmb.free_dlg(uac_r.dialog);
uac_r.dialog = 0;
}
else
{
if (subs->internal_update_flag == INTERNAL_UPDATE_TRUE)
{
LM_INFO("attempting to re-SUBSCRIBE on internal (rls_update_subs()) update - skipping\n");
if (dbmode != PUA_DB_ONLY)
lock_release(&HashT->p_records[hash_code].lock);
goto done;
}
if (presentity->to_tag.len == 0)
{
if (subs->expires > 0)
LM_WARN("attempting to re-SUBSCRIBE to a temporary (non-established) dialog - skipping\n");
else
{
LM_WARN("attempting to un-SUBSCRIBE from a temporary (non-established) dialog - skipping and deleting dialog\n");
if (dbmode==PUA_DB_ONLY)
delete_dialog_puadb(presentity);
else
delete_htable(presentity, hash_code);
}
if (dbmode != PUA_DB_ONLY)
lock_release(&HashT->p_records[hash_code].lock);
goto done;
}
td= pua_build_dlg_t(presentity);
if(td== NULL)
{
LM_ERR("while building tm dlg_t structure");
if (dbmode!=PUA_DB_ONLY)
lock_release(&HashT->p_records[hash_code].lock);
goto error;
}
hentity= subs_cbparam_indlg(presentity, expires, REQ_OTHER);
if(hentity== NULL)
{
LM_ERR("while building callback param\n");
if (dbmode!=PUA_DB_ONLY)
lock_release(&HashT->p_records[hash_code].lock);
goto error;
}
if (dbmode!=PUA_DB_ONLY)
lock_release(&HashT->p_records[hash_code].lock);
LM_DBG("event parameter: %d\n", hentity->event);
set_uac_req(&uac_r, &met, str_hdr, 0, td, TMCB_LOCAL_COMPLETED,
subs_cback_func, (void*)hentity);
result= tmb.t_request_within(&uac_r);
if(result< 0)
{
shm_free(hentity);
hentity= NULL;
LM_ERR("while sending request with t_request\n");
goto error;
}
}
done:
if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction)
{
if (pua_dbf.end_transaction(pua_db) < 0)
{
LM_ERR("in end_transaction\n");
goto error;
}
}
ret = 0;
error:
pua_free_tm_dlg(td);
pkg_free(str_hdr);
free_results_puadb(res);
if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction)
{
if (pua_dbf.abort_transaction(pua_db) < 0)
LM_ERR("in abort_transaction\n");
}
return ret;
}