/*
* $Id: send_subscribe.c 1666 2007-02-20 13:40:09Z anca_vamanu $
*
* pua module - presence user agent module
*
* Copyright (C) 2006 Voice Sistem S.R.L.
*
* This file is part of openser, a free SIP server.
*
* openser 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
*
* openser 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 "../tm/tm_load.h"
#include "../tm/dlg.h"
#include "../../parser/msg_parser.h"
#include "../../parser/parse_from.h"
#include "../../parser/parse_expires.h"
#include "hash.h"
#include "pua.h"
#include "send_subscribe.h"
extern int default_expires;
extern int min_expires;
void print_subs(subs_info_t* subs)
{
DBG("PUA:send_subscribe\tpres_uri= %.*s - len: %d\n",
subs->pres_uri->len, subs->pres_uri->s, subs->pres_uri->len );
DBG("PUA:send_subscribe\twatcher_uri= %.*s - len: %d\n",
subs->watcher_uri->len, subs->watcher_uri->s,
subs->watcher_uri->len);
}
str* subs_build_hdr(str* watcher_uri, int expires, int event)
{
str* str_hdr= NULL;
static char buf[3000];
char* subs_expires= NULL;
int len= 1;
str_hdr= (str*)pkg_malloc(sizeof(str));
if(str_hdr== NULL)
{
LOG(L_ERR, "PUA:subs_build_hdr:ERROR while allocating memory\n");
return NULL;
}
str_hdr->s= buf;
if(event& PRESENCE_EVENT)
{
memcpy(str_hdr->s ,"Event: presence", 15);
str_hdr->len = 15;
}
else
{
memcpy(str_hdr->s ,"Event: presence.winfo", 21);
str_hdr->len = 21;
}
memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
str_hdr->len += CRLF_LEN;
memcpy(str_hdr->s+ str_hdr->len ,"Contact: ", 9);
str_hdr->len += 9;
memcpy(str_hdr->s +str_hdr->len, watcher_uri->s,
watcher_uri->len);
str_hdr->len+= watcher_uri->len;
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+ 1, &len);
if(subs_expires == NULL || len == 0)
{
LOG(L_ERR, "PUA:subs_build_hdr: ERROR 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;
str_hdr->s[str_hdr->len]= '\0';
return str_hdr;
}
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+
2* presentity->pres_uri->len+ 1)* sizeof(char);
td = (dlg_t*)pkg_malloc(size);
if(td == NULL)
{
LOG(L_ERR, "PUA:pua_build_dlg_t: 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->pres_uri->s,
presentity->pres_uri->len) ;
td->rem_target.len = presentity->pres_uri->len;
size+= td->rem_target.len;
td->loc_seq.value = presentity->cseq ;
td->loc_seq.is_set = 1;
td->state= DLG_CONFIRMED ;
return td;
}
void subs_cback_func(struct cell *t, int type, struct tmcb_params *ps)
{
struct sip_msg* msg= NULL;
int lexpire= 0;
unsigned int cseq;
ua_pres_t* presentity= NULL;
struct to_body *pto, *pfrom = NULL, TO;
int size= 0;
unsigned int hash_code;
if( ps->param== NULL )
{
LOG(L_ERR, "PUA:subs_cback_func:ERROR null callback parameter\n");
return;
}
DBG("PUA:subs_cback_func: completed with status %d\n",ps->code) ;
if(ps->code >= 300 )
{
if( *ps->param== NULL )
{
LOG(L_ERR, "PUA:subs_cback_func: null callback parameter\n");
return;
}
hash_code= core_hash(((hentity_t*)(*ps->param))->pres_uri,
((hentity_t*)(*ps->param))->watcher_uri, HASH_SIZE);
lock_get(&HashT->p_records[hash_code].lock);
presentity= search_htable(((hentity_t*)(*ps->param))->pres_uri,
((hentity_t*)(*ps->param))->watcher_uri,
((hentity_t*)(*ps->param))->id ,
((hentity_t*)(*ps->param))->flag,
((hentity_t*)(*ps->param))->event, hash_code);
if(presentity)
delete_htable(presentity);
lock_release(&HashT->p_records[hash_code].lock);
goto done;
}
msg= ps->rpl;
if(msg == NULL || msg== FAKED_REPLY)
{
LOG(L_ERR, "PUA:subs_cback_func: no reply message found\n ");
goto done;
}
if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
{
LOG(L_ERR, "PUA:subs_cback_func: error parsing headers\n");
goto done;
}
if(ps->rpl->expires && msg->expires->body.len > 0)
{
if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
{
LOG(L_ERR, "PUA:subs_cback_func: ERROR cannot parse Expires"
" header\n");
goto done;
}
lexpire = ((exp_body_t*)msg->expires->parsed)->val;
DBG("PUA:subs_cback_func: lexpire= %d\n", lexpire);
}
if(lexpire== 0 && *ps->param== NULL )
{
DBG("PUA:subs_cback_func: Reply with expires= 0 and entity already"
" deleted\n");
return;
}
if( *ps->param== NULL )
{
LOG(L_ERR, "PUA:subs_cback_func:ERROR null callback parameter\n");
return;
}
hash_code= core_hash(((hentity_t*)(*ps->param))->pres_uri,
((hentity_t*)(*ps->param))->watcher_uri, HASH_SIZE);
lock_get(&HashT->p_records[hash_code].lock);
presentity= search_htable(((hentity_t*)(*ps->param))->pres_uri,
((hentity_t*)(*ps->param))->watcher_uri,
((hentity_t*)(*ps->param))->id,
((hentity_t*)(*ps->param))->flag,
((hentity_t*)(*ps->param))->event, hash_code);
if(presentity)
{
if(lexpire == 0 )
{
DBG("PUA:subs_cback_func: lexpire= 0 Delete from hash table");
delete_htable(presentity );
lock_release(&HashT->p_records[hash_code].lock);
goto done;
}
DBG("PUA:subs_cback_func: *** Update expires\n");
update_htable(presentity, ((hentity_t*)(*ps->param))->desired_expires, lexpire, hash_code);
lock_release(&HashT->p_records[hash_code].lock);
goto done;
}
lock_release(&HashT->p_records[hash_code].lock);
/* if a new subscribe -> insert */
if(lexpire== 0)
{
LOG(L_ERR, "PUA: subs_cback_func:expires= 0: no not insert\n");
goto done;
}
/* get dialog information */
if( msg->callid==NULL || msg->callid->body.s==NULL)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR cannot parse callid"
" header\n");
goto done;
}
if( msg->cseq==NULL || msg->cseq->body.s==NULL)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR cannot parse cseq"
" header\n");
goto done;
}
if( str2int( &(get_cseq(msg)->number), &cseq)< 0)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR while converting str"
" to int\n");
}
if (!msg->from || !msg->from->body.s)
{
DBG("PUA:subs_cback_func: ERROR cannot find 'from' header!\n");
goto done;
}
if (msg->from->parsed == NULL)
{
if ( parse_from_header( msg )<0 )
{
DBG("PUA:subs_cback_func: ERROR cannot parse From header\n");
goto done;
}
}
pfrom = (struct to_body*)msg->from->parsed;
if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR no from tag value"
" present\n");
goto done;
}
if( msg->to==NULL || msg->to->body.s==NULL)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR cannot parse TO"
" header\n");
goto done;
}
if(msg->to->parsed != NULL)
{
pto = (struct to_body*)msg->to->parsed;
DBG("PUA: subs_cback_func: 'To' header ALREADY PARSED: <%.*s>\n",
pto->uri.len, pto->uri.s );
}
else
{
memset( &TO , 0, sizeof(TO) );
parse_to(msg->to->body.s,msg->to->body.s +
msg->to->body.len + 1, &TO);
if(TO.uri.len <= 0)
{
DBG("PUA: subs_cback_func: 'To' header NOT parsed\n");
goto done;
}
pto = &TO;
}
if( pto->tag_value.s ==NULL || pto->tag_value.len == 0)
{
LOG(L_ERR, "PUA: subs_cback_func: ERROR no from tag value"
" present\n");
goto done;
}
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+ 1 )*sizeof(char);
presentity= (ua_pres_t*)shm_malloc(size);
if(presentity== NULL)
{
LOG(L_ERR, "PUA: subs_cback_func: Error no more share memory");
goto done;
}
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;
presentity->event|= ((hentity_t*)(*ps->param))->event;
presentity->flag|= ((hentity_t*)(*ps->param))->flag;
presentity->db_flag|= INSERTDB_FLAG;
presentity->etag.s= NULL;
presentity->cseq= cseq;
presentity->desired_expires= ((hentity_t*)(*ps->param))->desired_expires;
presentity->expires= lexpire+ (int)time(NULL);
insert_htable(presentity);
shm_free(*ps->param);
(*ps->param)= NULL;
return ;
done:
if(*ps->param)
{
shm_free(*ps->param);
*ps->param= NULL;
}
return;
}
hentity_t* build_cback_param(subs_info_t* subs)
{
hentity_t* hentity= NULL;
int size;
size= sizeof(hentity_t)+ 2*sizeof(str)+(subs->pres_uri->len+
subs->watcher_uri->len+ 1)* sizeof(char);
hentity= (hentity_t*)shm_malloc(size);
if(hentity== NULL)
{
LOG(L_ERR, "PUA: build_cback_param: No more share memory\n");
return NULL;
}
memset(hentity, 0, size);
size= sizeof(hentity_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;
if(subs->expires< 0)
hentity->desired_expires= 0;
else
hentity->desired_expires=subs->expires+ (int)time(NULL);
hentity->desired_expires= subs->expires+ (int)time(NULL);
hentity->flag|= subs->source_flag;
hentity->event|= subs->event;
return hentity;
}
int send_subscribe(subs_info_t* subs)
{
ua_pres_t* presentity= NULL;
str met= {"SUBSCRIBE", 9};
str* str_hdr= NULL;
int ret= 0;
unsigned int hash_code;
hentity_t* hentity= NULL;
int expires;
DBG("send_subscribe... \n");
print_subs(subs);
if(subs->expires< 0)
expires= 3600;
else
expires= subs->expires;
str_hdr= subs_build_hdr(subs->watcher_uri, expires, subs->event);
if(str_hdr== NULL || str_hdr->s== NULL)
{
LOG(L_ERR, "PUA:send_subscribe: Error while building extra headers\n");
return -1;
}
hash_code=core_hash(subs->pres_uri, subs->watcher_uri, HASH_SIZE);
lock_get(&HashT->p_records[hash_code].lock);
presentity= search_htable(subs->pres_uri, subs->watcher_uri,
subs->id, subs->source_flag, subs->event, hash_code);
if(presentity== NULL )
{
lock_release(&HashT->p_records[hash_code].lock);
if(subs->flag & UPDATE_TYPE)
{
LOG(L_ERR,"PUA:send_subscribe: UNSUBS_FLAG and no record found\n");
goto done;
}
hentity= build_cback_param(subs);
if(hentity== NULL)
{
LOG(L_ERR, "PUA:send_subscribe:ERROR while building callback"
" param\n");
ret= -1;
goto done;
}
tmb.t_request
(&met, /* Type of the message */
subs->pres_uri, /* Request-URI */
subs->pres_uri, /* To */
subs->watcher_uri, /* From */
str_hdr, /* Optional headers including CRLF */
0, /* Message body */
subs_cback_func, /* Callback function */
(void*)hentity /* Callback parameter */
);
}
else
{
dlg_t* td= NULL;
td= pua_build_dlg_t(presentity);
if(td== NULL)
{
LOG(L_ERR, "PUA:send_subscribe: Error while building tm dlg_t"
"structure");
ret= -1;
lock_release(&HashT->p_records[hash_code].lock);
shm_free(hentity);
goto done;
}
if(subs->expires== 0)
{
delete_htable(presentity);
}
else
{
hentity= build_cback_param(subs);
if(hentity== NULL)
{
LOG(L_ERR, "PUA:send_subscribe:ERROR while building callback"
" param\n");
lock_release(&HashT->p_records[hash_code].lock);
ret= -1;
goto done;
}
}
lock_release(&HashT->p_records[hash_code].lock);
tmb.t_request_within
(&met,
str_hdr,
0,
td,
subs_cback_func,
(void*)hentity
);
pkg_free(td);
td= NULL;
}
done:
pkg_free(str_hdr);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1