mirror of https://github.com/sipwise/kamailio.git
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.
656 lines
16 KiB
656 lines
16 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Accounting module logic
|
|
*
|
|
* Copyright (C) 2001-2003 FhG Fokus
|
|
* Copyright (C) 2006 Voice Sistem SRL
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* History:
|
|
* -------
|
|
* 2006-09-19 forked from the acc_mod.c file during a big re-structuring
|
|
* of acc module (bogdan)
|
|
*/
|
|
|
|
/*! \file
|
|
* \ingroup acc
|
|
* \brief Acc:: Logic
|
|
*
|
|
* - Module: \ref acc
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "../../dprint.h"
|
|
#include "../../sr_module.h"
|
|
#include "../../parser/parse_from.h"
|
|
#include "../../parser/parse_content.h"
|
|
#include "../../lib/kcore/cmpapi.h"
|
|
#include "../../modules/tm/tm_load.h"
|
|
#include "../rr/api.h"
|
|
#include "../../flags.h"
|
|
#include "acc.h"
|
|
#include "acc_api.h"
|
|
#include "acc_mod.h"
|
|
#include "acc_logic.h"
|
|
|
|
extern struct tm_binds tmb;
|
|
extern struct rr_binds rrb;
|
|
|
|
struct acc_enviroment acc_env;
|
|
|
|
|
|
#define is_acc_flag_set(_rq,_flag) (((_flag) != -1) && (isflagset((_rq), (_flag)) == 1))
|
|
#define reset_acc_flag(_rq,_flag) (resetflag((_rq), (_flag)))
|
|
|
|
#define is_failed_acc_on(_rq) is_acc_flag_set(_rq,failed_transaction_flag)
|
|
|
|
#define is_log_acc_on(_rq) is_acc_flag_set(_rq,log_flag)
|
|
#define is_log_mc_on(_rq) is_acc_flag_set(_rq,log_missed_flag)
|
|
|
|
#ifdef SQL_ACC
|
|
#define is_db_acc_on(_rq) is_acc_flag_set(_rq,db_flag)
|
|
#define is_db_mc_on(_rq) is_acc_flag_set(_rq,db_missed_flag)
|
|
#else
|
|
#define is_db_acc_on(_rq) (0)
|
|
#define is_db_mc_on(_rq) (0)
|
|
#endif
|
|
|
|
#ifdef RAD_ACC
|
|
#define is_rad_acc_on(_rq) is_acc_flag_set(_rq,radius_flag)
|
|
#define is_rad_mc_on(_rq) is_acc_flag_set(_rq,radius_missed_flag)
|
|
#else
|
|
#define is_rad_acc_on(_rq) (0)
|
|
#define is_rad_mc_on(_rq) (0)
|
|
#endif
|
|
|
|
|
|
#ifdef DIAM_ACC
|
|
#define is_diam_acc_on(_rq) is_acc_flag_set(_rq,diameter_flag)
|
|
#define is_diam_mc_on(_rq) is_acc_flag_set(_rq,diameter_missed_flag)
|
|
#else
|
|
#define is_diam_acc_on(_rq) (0)
|
|
#define is_diam_mc_on(_rq) (0)
|
|
#endif
|
|
|
|
#define is_acc_on(_rq) \
|
|
( (is_log_acc_on(_rq)) || (is_db_acc_on(_rq)) \
|
|
|| (is_rad_acc_on(_rq)) || (is_diam_acc_on(_rq)) )
|
|
|
|
#define is_mc_on(_rq) \
|
|
( (is_log_mc_on(_rq)) || (is_db_mc_on(_rq)) \
|
|
|| (is_rad_mc_on(_rq)) || (is_diam_mc_on(_rq)) )
|
|
|
|
#define skip_cancel(_rq) \
|
|
(((_rq)->REQ_METHOD==METHOD_CANCEL) && report_cancels==0)
|
|
|
|
#define is_acc_prepare_on(_rq) \
|
|
(acc_prepare_always || is_acc_flag_set(_rq,acc_prepare_flag))
|
|
|
|
static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps );
|
|
|
|
|
|
static inline struct hdr_field* get_rpl_to( struct cell *t,
|
|
struct sip_msg *reply)
|
|
{
|
|
if (reply==FAKED_REPLY || !reply || !reply->to)
|
|
return t->uas.request->to;
|
|
else
|
|
return reply->to;
|
|
}
|
|
|
|
|
|
static inline void env_set_to(struct hdr_field *to)
|
|
{
|
|
acc_env.to = to;
|
|
}
|
|
|
|
|
|
static inline void env_set_text(char *p, int len)
|
|
{
|
|
acc_env.text.s = p;
|
|
acc_env.text.len = len;
|
|
}
|
|
|
|
|
|
static inline void env_set_code_status( int code, struct sip_msg *reply)
|
|
{
|
|
static char code_buf[INT2STR_MAX_LEN];
|
|
str reason = {"Reason", 6};
|
|
struct hdr_field *hf;
|
|
|
|
acc_env.code = code;
|
|
if (reply==FAKED_REPLY || reply==NULL) {
|
|
/* code */
|
|
acc_env.code_s.s =
|
|
int2bstr((unsigned long)code, code_buf, &acc_env.code_s.len);
|
|
/* reason */
|
|
acc_env.reason.s = error_text(code);
|
|
acc_env.reason.len = strlen(acc_env.reason.s);
|
|
} else {
|
|
acc_env.code_s = reply->first_line.u.reply.status;
|
|
hf = NULL;
|
|
if (reason_from_hf) {
|
|
/* TODO: take reason from all Reason headers */
|
|
if(parse_headers(reply, HDR_EOH_F, 0) < 0) {
|
|
LM_ERR("error parsing headers\n");
|
|
} else {
|
|
for (hf=reply->headers; hf; hf=hf->next) {
|
|
if (cmp_hdrname_str(&hf->name, &reason)==0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (hf == NULL) {
|
|
acc_env.reason = reply->first_line.u.reply.reason;
|
|
} else {
|
|
acc_env.reason = hf->body;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static inline void env_set_comment(struct acc_param *accp)
|
|
{
|
|
acc_env.code = accp->code;
|
|
acc_env.code_s = accp->code_s;
|
|
acc_env.reason = accp->reason;
|
|
}
|
|
|
|
|
|
static inline int acc_preparse_req(struct sip_msg *req)
|
|
{
|
|
if ( (parse_headers(req,HDR_CALLID_F|HDR_CSEQ_F|HDR_FROM_F|HDR_TO_F,0)<0)
|
|
|| (parse_from_header(req)<0 ) ) {
|
|
LM_ERR("failed to preparse request\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int acc_parse_code(char *p, struct acc_param *param)
|
|
{
|
|
if (p==NULL||param==NULL)
|
|
return -1;
|
|
|
|
/* any code? */
|
|
if (param->reason.len>=3 && isdigit((int)p[0])
|
|
&& isdigit((int)p[1]) && isdigit((int)p[2]) ) {
|
|
param->code = (p[0]-'0')*100 + (p[1]-'0')*10 + (p[2]-'0');
|
|
param->code_s.s = p;
|
|
param->code_s.len = 3;
|
|
param->reason.s += 3;
|
|
for( ; isspace((int)param->reason.s[0]) ; param->reason.s++ );
|
|
param->reason.len = strlen(param->reason.s);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int acc_get_param_value(struct sip_msg *rq, struct acc_param *param)
|
|
{
|
|
if(param->elem!=NULL) {
|
|
if(pv_printf_s(rq, param->elem, ¶m->reason)==-1) {
|
|
LM_ERR("Can't get value for %.*s\n", param->reason.len, param->reason.s);
|
|
return -1;
|
|
}
|
|
if(acc_parse_code(param->reason.s, param)<0)
|
|
{
|
|
LM_ERR("Can't parse code\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int w_acc_log_request(struct sip_msg *rq, char *comment, char *foo)
|
|
{
|
|
struct acc_param *param = (struct acc_param*)comment;
|
|
if (acc_preparse_req(rq)<0)
|
|
return -1;
|
|
if(acc_get_param_value(rq, param)<0)
|
|
return -1;
|
|
env_set_to( rq->to );
|
|
env_set_comment(param);
|
|
env_set_text( ACC_REQUEST, ACC_REQUEST_LEN);
|
|
return acc_log_request(rq);
|
|
}
|
|
|
|
|
|
#ifdef SQL_ACC
|
|
int acc_db_set_table_name(struct sip_msg *msg, void *param, str *table)
|
|
{
|
|
#define DB_TABLE_NAME_SIZE 64
|
|
static char db_table_name_buf[DB_TABLE_NAME_SIZE];
|
|
str dbtable;
|
|
|
|
if(param!=NULL) {
|
|
if(get_str_fparam(&dbtable, msg, (fparam_t*)param)<0) {
|
|
LM_ERR("cannot get acc db table name\n");
|
|
return -1;
|
|
}
|
|
if(dbtable.len>=DB_TABLE_NAME_SIZE) {
|
|
LM_ERR("acc db table name too big [%.*s] max %d\n",
|
|
dbtable.len, dbtable.s, DB_TABLE_NAME_SIZE);
|
|
return -1;
|
|
}
|
|
strncpy(db_table_name_buf, dbtable.s, dbtable.len);
|
|
db_table_name_buf[dbtable.len] = '\0';
|
|
env_set_text(db_table_name_buf, dbtable.len);
|
|
} else {
|
|
if(table==NULL) {
|
|
LM_ERR("no acc table name\n");
|
|
return -1;
|
|
}
|
|
env_set_text(table->s, table->len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int w_acc_db_request(struct sip_msg *rq, char *comment, char *table)
|
|
{
|
|
struct acc_param *param = (struct acc_param*)comment;
|
|
if (!table) {
|
|
LM_ERR("db support not configured\n");
|
|
return -1;
|
|
}
|
|
if (acc_preparse_req(rq)<0)
|
|
return -1;
|
|
if(acc_db_set_table_name(rq, (void*)table, NULL)<0) {
|
|
LM_ERR("cannot set table name\n");
|
|
return -1;
|
|
}
|
|
if(acc_get_param_value(rq, param)<0)
|
|
return -1;
|
|
env_set_to( rq->to );
|
|
env_set_comment(param);
|
|
return acc_db_request(rq);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef RAD_ACC
|
|
int w_acc_rad_request(struct sip_msg *rq, char *comment, char *foo)
|
|
{
|
|
struct acc_param *param = (struct acc_param*)comment;
|
|
if (acc_preparse_req(rq)<0)
|
|
return -1;
|
|
if(acc_get_param_value(rq, param)<0)
|
|
return -1;
|
|
env_set_to( rq->to );
|
|
env_set_comment(param);
|
|
return acc_rad_request(rq);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef DIAM_ACC
|
|
int w_acc_diam_request(struct sip_msg *rq, char *comment, char *foo)
|
|
{
|
|
struct acc_param *param = (struct acc_param*)comment;
|
|
if (acc_preparse_req(rq)<0)
|
|
return -1;
|
|
if(acc_get_param_value(rq, param)<0)
|
|
return -1;
|
|
env_set_to( rq->to );
|
|
env_set_comment(param);
|
|
return acc_diam_request(rq);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/* prepare message and transaction context for later accounting */
|
|
void acc_onreq( struct cell* t, int type, struct tmcb_params *ps )
|
|
{
|
|
int tmcb_types;
|
|
int is_invite;
|
|
|
|
if ( ps->req && !skip_cancel(ps->req) &&
|
|
( is_acc_on(ps->req) || is_mc_on(ps->req)
|
|
|| is_acc_prepare_on(ps->req) ) ) {
|
|
/* do some parsing in advance */
|
|
if (acc_preparse_req(ps->req)<0)
|
|
return;
|
|
is_invite = (ps->req->REQ_METHOD==METHOD_INVITE)?1:0;
|
|
/* install additional handlers */
|
|
tmcb_types =
|
|
/* report on completed transactions */
|
|
TMCB_RESPONSE_OUT |
|
|
/* account e2e acks if configured to do so */
|
|
((report_ack && is_acc_on(ps->req))?TMCB_E2EACK_IN:0) |
|
|
/* get incoming replies ready for processing */
|
|
TMCB_RESPONSE_IN |
|
|
/* report on missed calls */
|
|
((is_invite && (is_mc_on(ps->req)
|
|
|| is_acc_prepare_on(ps->req)))?TMCB_ON_FAILURE:0);
|
|
if (tmb.register_tmcb( 0, t, tmcb_types, tmcb_func, 0, 0 )<=0) {
|
|
LM_ERR("cannot register additional callbacks\n");
|
|
return;
|
|
}
|
|
/* if required, determine request direction */
|
|
if( detect_direction && !rrb.is_direction(ps->req,RR_FLOW_UPSTREAM) ) {
|
|
LM_DBG("detected an UPSTREAM req -> flaging it\n");
|
|
ps->req->msg_flags |= FL_REQ_UPSTREAM;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* is this reply of interest for accounting ? */
|
|
static inline int should_acc_reply(struct sip_msg *req, struct sip_msg *rpl,
|
|
int code)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* negative transactions reported otherwise only if explicitly
|
|
* demanded */
|
|
|
|
if (code >= 300) {
|
|
if (!is_failed_acc_on(req)) return 0;
|
|
i = 0;
|
|
while (failed_filter[i] != 0) {
|
|
if (failed_filter[i] == code) return 0;
|
|
i++;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if ( !is_acc_on(req) )
|
|
return 0;
|
|
|
|
if ( code<200 && !(early_media &&
|
|
parse_headers(rpl,HDR_CONTENTLENGTH_F, 0) == 0 &&
|
|
rpl->content_length && get_content_length(rpl) > 0))
|
|
return 0;
|
|
|
|
return 1; /* seed is through, we will account this reply */
|
|
}
|
|
|
|
|
|
|
|
/* parse incoming replies before cloning */
|
|
static inline void acc_onreply_in(struct cell *t, struct sip_msg *req,
|
|
struct sip_msg *reply, int code)
|
|
{
|
|
/* don't parse replies in which we are not interested */
|
|
/* missed calls enabled ? */
|
|
if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code)
|
|
|| (is_invite(t) && code>=300 && is_mc_on(req))) ) {
|
|
parse_headers(reply, HDR_TO_F, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* initiate a report if we previously enabled MC accounting for this t */
|
|
static inline void on_missed(struct cell *t, struct sip_msg *req,
|
|
struct sip_msg *reply, int code)
|
|
{
|
|
str new_uri_bk = {0, 0};
|
|
int flags_to_reset = 0;
|
|
int br = -1;
|
|
|
|
/* get winning branch index, if set */
|
|
if (t->relayed_reply_branch>=0) {
|
|
br = t->relayed_reply_branch;
|
|
} else {
|
|
if(code>=300) {
|
|
br = tmb.t_get_picked_branch();
|
|
}
|
|
}
|
|
/* set as new_uri the one from selected branch */
|
|
if (br>=0) {
|
|
new_uri_bk = req->new_uri;
|
|
req->new_uri = t->uac[br].uri;
|
|
req->parsed_uri_ok = 0;
|
|
} else {
|
|
new_uri_bk.len = -1;
|
|
new_uri_bk.s = 0;
|
|
}
|
|
|
|
/* set env variables */
|
|
env_set_to( get_rpl_to(t,reply) );
|
|
env_set_code_status( code, reply);
|
|
|
|
/* we report on missed calls when the first
|
|
* forwarding attempt fails; we do not wish to
|
|
* report on every attempt; so we clear the flags;
|
|
*/
|
|
|
|
if (is_log_mc_on(req)) {
|
|
env_set_text( ACC_MISSED, ACC_MISSED_LEN);
|
|
acc_log_request( req );
|
|
flags_to_reset |= log_missed_flag;
|
|
}
|
|
#ifdef SQL_ACC
|
|
if (is_db_mc_on(req)) {
|
|
if(acc_db_set_table_name(req, db_table_mc_data, &db_table_mc)<0) {
|
|
LM_ERR("cannot set missed call db table name\n");
|
|
return;
|
|
}
|
|
acc_db_request( req );
|
|
flags_to_reset |= db_missed_flag;
|
|
}
|
|
#endif
|
|
#ifdef RAD_ACC
|
|
if (is_rad_mc_on(req)) {
|
|
acc_rad_request( req );
|
|
flags_to_reset |= radius_missed_flag;
|
|
}
|
|
#endif
|
|
/* DIAMETER */
|
|
#ifdef DIAM_ACC
|
|
if (is_diam_mc_on(req)) {
|
|
acc_diam_request( req );
|
|
flags_to_reset |= diameter_missed_flag;
|
|
}
|
|
#endif
|
|
|
|
/* run extra acc engines */
|
|
acc_run_engines(req, 1, &flags_to_reset);
|
|
|
|
/* Reset the accounting missed_flags
|
|
* These can't be reset in the blocks above, because
|
|
* it would skip accounting if the flags are identical
|
|
*/
|
|
reset_acc_flag( req, flags_to_reset );
|
|
|
|
if (new_uri_bk.len>=0) {
|
|
req->new_uri = new_uri_bk;
|
|
req->parsed_uri_ok = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
extern int _acc_clone_msg;
|
|
|
|
/* initiate a report if we previously enabled accounting for this t */
|
|
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
|
|
struct sip_msg *reply, int code)
|
|
{
|
|
str new_uri_bk;
|
|
int br = -1;
|
|
hdr_field_t *hdr;
|
|
sip_msg_t tmsg;
|
|
sip_msg_t *preq;
|
|
|
|
/* acc_onreply is bound to TMCB_REPLY which may be called
|
|
from _reply, like when FR hits; we should not miss this
|
|
event for missed calls either */
|
|
if (is_invite(t) && code>=300 && is_mc_on(req) )
|
|
on_missed(t, req, reply, code);
|
|
|
|
if (!should_acc_reply(req, reply, code))
|
|
return;
|
|
|
|
if(_acc_clone_msg==1) {
|
|
memcpy(&tmsg, req, sizeof(sip_msg_t));
|
|
preq = &tmsg;
|
|
} else {
|
|
preq = req;
|
|
}
|
|
|
|
/* get winning branch index, if set */
|
|
if (t->relayed_reply_branch>=0) {
|
|
br = t->relayed_reply_branch;
|
|
} else {
|
|
if(code>=300) {
|
|
br = tmb.t_get_picked_branch();
|
|
}
|
|
}
|
|
|
|
/* for reply processing, set as new_uri the one from selected branch */
|
|
if (br>=0) {
|
|
new_uri_bk = preq->new_uri;
|
|
preq->new_uri = t->uac[br].uri;
|
|
preq->parsed_uri_ok = 0;
|
|
} else {
|
|
new_uri_bk.len = -1;
|
|
new_uri_bk.s = 0;
|
|
}
|
|
/* set env variables */
|
|
env_set_to( get_rpl_to(t,reply) );
|
|
env_set_code_status( code, reply);
|
|
|
|
if ( is_log_acc_on(preq) ) {
|
|
env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
|
|
acc_log_request(preq);
|
|
}
|
|
#ifdef SQL_ACC
|
|
if (is_db_acc_on(preq)) {
|
|
if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
|
|
LM_ERR("cannot set acc db table name\n");
|
|
} else {
|
|
acc_db_request(preq);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef RAD_ACC
|
|
if (is_rad_acc_on(preq))
|
|
acc_rad_request(preq);
|
|
#endif
|
|
/* DIAMETER */
|
|
#ifdef DIAM_ACC
|
|
if (is_diam_acc_on(preq))
|
|
acc_diam_request(preq);
|
|
#endif
|
|
|
|
/* run extra acc engines */
|
|
acc_run_engines(preq, 0, NULL);
|
|
|
|
if (new_uri_bk.len>=0) {
|
|
req->new_uri = new_uri_bk;
|
|
req->parsed_uri_ok = 0;
|
|
}
|
|
|
|
/* free header's parsed structures that were added by resolving acc attributes */
|
|
for( hdr=req->headers ; hdr ; hdr=hdr->next ) {
|
|
if ( hdr->parsed && hdr_allocs_parse(hdr) &&
|
|
(hdr->parsed<(void*)t->uas.request ||
|
|
hdr->parsed>=(void*)t->uas.end_request)) {
|
|
/* header parsed filed doesn't point inside uas.request memory
|
|
* chunck -> it was added by resolving acc attributes -> free it as pkg */
|
|
DBG("removing hdr->parsed %d\n", hdr->type);
|
|
clean_hdr_field(hdr);
|
|
hdr->parsed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static inline void acc_onack( struct cell* t, struct sip_msg *req,
|
|
struct sip_msg *ack, int code)
|
|
{
|
|
if (acc_preparse_req(ack)<0)
|
|
return;
|
|
|
|
/* set env variables */
|
|
env_set_to( ack->to?ack->to:req->to );
|
|
env_set_code_status( t->uas.status, 0 );
|
|
|
|
if (is_log_acc_on(req)) {
|
|
env_set_text( ACC_ACKED, ACC_ACKED_LEN);
|
|
acc_log_request( ack );
|
|
}
|
|
#ifdef SQL_ACC
|
|
if (is_db_acc_on(req)) {
|
|
if(acc_db_set_table_name(ack, db_table_acc_data, &db_table_acc)<0) {
|
|
LM_ERR("cannot set acc db table name\n");
|
|
return;
|
|
}
|
|
acc_db_request( ack );
|
|
}
|
|
#endif
|
|
#ifdef RAD_ACC
|
|
if (is_rad_acc_on(req)) {
|
|
acc_rad_request(ack);
|
|
}
|
|
#endif
|
|
/* DIAMETER */
|
|
#ifdef DIAM_ACC
|
|
if (is_diam_acc_on(req)) {
|
|
acc_diam_request(ack);
|
|
}
|
|
#endif
|
|
|
|
/* run extra acc engines */
|
|
acc_run_engines(ack, 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief execute an acc event via a specific engine
|
|
*/
|
|
int acc_api_exec(struct sip_msg *rq, acc_engine_t *eng,
|
|
acc_param_t* comment)
|
|
{
|
|
acc_info_t inf;
|
|
if (acc_preparse_req(rq)<0)
|
|
return -1;
|
|
env_set_to(rq->to);
|
|
env_set_comment(comment);
|
|
memset(&inf, 0, sizeof(acc_info_t));
|
|
inf.env = &acc_env;
|
|
acc_api_set_arrays(&inf);
|
|
return eng->acc_req(rq, &inf);
|
|
}
|
|
|
|
|
|
static void tmcb_func( struct cell* t, int type, struct tmcb_params *ps )
|
|
{
|
|
LM_DBG("acc callback called for t(%p) event type %d, reply code %d\n",
|
|
t, type, ps->code);
|
|
if (type&TMCB_RESPONSE_OUT) {
|
|
acc_onreply( t, ps->req, ps->rpl, ps->code);
|
|
} else if (type&TMCB_E2EACK_IN) {
|
|
acc_onack( t, t->uas.request, ps->req, ps->code);
|
|
} else if (type&TMCB_ON_FAILURE) {
|
|
on_missed( t, ps->req, ps->rpl, ps->code);
|
|
} else if (type&TMCB_RESPONSE_IN) {
|
|
acc_onreply_in( t, ps->req, ps->rpl, ps->code);
|
|
}
|
|
}
|
|
|