Imported Upstream version 4.3.3

changes/23/2823/2 upstream/4.3.3
Victor Seva 11 years ago
parent a88ca52b70
commit 453a2eb8e3

File diff suppressed because it is too large Load Diff

@ -997,9 +997,11 @@ install_initd_centos install-initd-centos:
-e "s#GROUP=kamailio#GROUP=$(NAME)#g" \
< pkg/kamailio/rpm/kamailio.default \
> /etc/default/$(NAME)
mkdir -p /var/run/$(NAME)
/usr/sbin/groupadd -r $(NAME)
/usr/sbin/useradd -r -g $(NAME) -s /bin/false -c "Kamailio Daemon" \
-d /var/run/$(NAME) $(NAME)
chown $(NAME):$(NAME) /var/run/$(NAME)
.PHONY: dbschema
dbschema:

@ -96,13 +96,13 @@ INSTALL_FLAVOUR=$(FLAVOUR)
# version number
VERSION = 4
PATCHLEVEL = 3
SUBLEVEL = 1
SUBLEVEL = 3
# memory manager switcher
# 0 - f_malloc (fast malloc)
# 1 - q_malloc (quick malloc)
# 2 - tlsf_malloc (O(1) malloc and free)
MEMMNG ?= 0
MEMMNG ?= 1
# memory debugger switcher
# 0 - off (no-debug mode)
# 1 - on (debug mode)
@ -433,7 +433,8 @@ doxygen_dir=doc/doxygen
BASEDIR ?= $(DESTDIR)
basedir = $(BASEDIR)
runbasedir = $(BASEDIR)
RUNBASEDIR ?= $(DESTDIR)
runbasedir = $(RUNBASEDIR)
# install location
PREFIX ?= $(LOCALBASE)
@ -1317,12 +1318,13 @@ ifeq ($(CC_NAME), gcc)
CFLAGS= -mips2 $(CC_OPT) -funroll-loops $(PROFILE)
#if gcc 5.0+, 4.5+ or 4.2+
ifeq (,$(strip $(filter-out 4.2+ 4.5+ 5.0+,$(CC_SHORTVER))))
CFLAGS+=-minline-all-stringops -ftree-vectorize \
-fno-strict-overflow
CFLAGS+=-ftree-vectorize -fno-strict-overflow
# not supported on mips: -minline-all-stringops
else
#if gcc 4.0+
ifeq ($(CC_SHORTVER), 4.x)
CFLAGS+=-minline-all-stringops -ftree-vectorize
CFLAGS+=-ftree-vectorize
# not supported on mips: -minline-all-stringops
else
#if gcc 3.4+
ifeq ($(CC_SHORTVER), 3.4)
@ -1362,12 +1364,14 @@ ifeq ($(CC_NAME), gcc)
CFLAGS= -mips64 $(CC_OPT) -funroll-loops $(PROFILE)
#if gcc 5.0+, 4.5+ or 4.2+
ifeq (,$(strip $(filter-out 4.2+ 4.5+ 5.0+,$(CC_SHORTVER))))
CFLAGS+=-minline-all-stringops -ftree-vectorize \
-fno-strict-overflow
CFLAGS+=-ftree-vectorize -fno-strict-overflow
# not supported on mips: -minline-all-stringops
else
#if gcc 4.0+
ifeq ($(CC_SHORTVER), 4.x)
CFLAGS+=-minline-all-stringops -ftree-vectorize
CFLAGS+=-ftree-vectorize
# not supported on mips: -minline-all-stringops
else
#if gcc 3.4+
ifeq ($(CC_SHORTVER), 3.4)

@ -2,6 +2,6 @@
* DO NOT EDIT IT
*/
#define REPO_VER "f38e67"
#define REPO_HASH "f38e67"
#define REPO_VER "e275bc"
#define REPO_HASH "e275bc"
#define REPO_STATE ""

@ -925,7 +925,7 @@ static void core_sockets_list(rpc_t* rpc, void* c)
rpc->struct_add(ha, "ss",
"address", ai->address_str.s);
rpc->struct_add(ha, "sss",
"proto", si->port_no_str.s,
"port", si->port_no_str.s,
"mcast", si->flags & SI_IS_MCAST ? "yes" : "no",
"mhomed", si->flags & SI_IS_MHOMED ? "yes" : "no");
} else {
@ -939,7 +939,7 @@ static void core_sockets_list(rpc_t* rpc, void* c)
rpc->struct_add(ha, "s",
"ipaddress", si->address_str.s);
rpc->struct_add(ha, "sss",
"proto", si->port_no_str.s,
"port", si->port_no_str.s,
"mcast", si->flags & SI_IS_MCAST ? "yes" : "no",
"mhomed", si->flags & SI_IS_MHOMED ? "yes" : "no");
}

@ -893,3 +893,22 @@ int uri_restore_rcv_alias(str *uri, str *nuri, str *suri)
return 0;
}
/* address of record (aor) management */
/* address of record considered case sensitive
* - 0 = no; 1 = yes */
static int aor_case_sensitive=0;
int set_aor_case_sensitive(int mode)
{
int r;
r = aor_case_sensitive;
aor_case_sensitive = mode;
return r;
}
int get_aor_case_sensitive(void)
{
return aor_case_sensitive;
}

@ -258,4 +258,8 @@ int uri_restore_rcv_alias(str *uri, str *nuri, str *suri);
int init_dst_set(void);
int set_aor_case_sensitive(int mode);
int get_aor_case_sensitive(void);
#endif /* _DSET_H */

@ -546,7 +546,7 @@ route[RELAY] {
# Per SIP request initial checks
route[REQINIT] {
#!ifdef WITH_ANTIFLOOD
# flood dection from same IP and traffic ban for a while
# flood detection from same IP and traffic ban for a while
# be sure you exclude checking trusted peers, such as pstn gateways
# - local host excluded (e.g., loop to self)
if(src_ip!=myself) {
@ -721,7 +721,7 @@ route[PRESENCE] {
return;
}
# IP authorization and user uthentication
# IP authorization and user authentication
route[AUTH] {
#!ifdef WITH_AUTH
@ -771,7 +771,7 @@ route[NATDETECT] {
return;
}
# RTPProxy control and singaling updates for NAT traversal
# RTPProxy control and signaling updates for NAT traversal
route[NATMANAGE] {
#!ifdef WITH_NAT
if (is_request()) {
@ -827,7 +827,7 @@ route[PSTN] {
#!ifdef WITH_PSTN
# check if PSTN GW IP is defined
if (strempty($sel(cfg_get.pstn.gw_ip))) {
xlog("SCRIPT: PSTN rotuing enabled but pstn.gw_ip not defined\n");
xlog("SCRIPT: PSTN routing enabled but pstn.gw_ip not defined\n");
return;
}
@ -884,7 +884,7 @@ route[TOVOICEMAIL] {
# check if VoiceMail server IP is defined
if (strempty($sel(cfg_get.voicemail.srv_ip))) {
xlog("SCRIPT: VoiceMail rotuing enabled but IP not defined\n");
xlog("SCRIPT: VoiceMail routing enabled but IP not defined\n");
return;
}
if(is_method("INVITE")) {

@ -815,7 +815,7 @@ int binrpc_print_response(struct binrpc_response_handle *resp_handle, char* fmt)
read_value:
val.name.s=0;
val.name.len=0;
p=binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
p=binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
if (ret<0){
if (fmt)
putchar('\n');
@ -898,7 +898,7 @@ int binrpc_parse_response(struct binrpc_val** vals, int* val_count,
val.type = BINRPC_T_ALL;
val.name.s = 0;
val.name.len = 0;
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
if (ret<0){
if (ret==E_BINRPC_EOP){
break;
@ -982,7 +982,7 @@ int binrpc_parse_error_response(
val.type=BINRPC_T_INT;
val.name.s=0;
val.name.len=0;
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
if (ret < 0) {
snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
"parse_error_response: error when parsing reply (code): %s", binrpc_error(ret)
@ -992,7 +992,7 @@ int binrpc_parse_error_response(
*err_no = val.u.intval;
val.type=BINRPC_T_STR;
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
if (ret < 0) {
snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
"parse_error_response: error when parsing reply (str): %s", binrpc_error(ret)
@ -1170,7 +1170,7 @@ int binrpc_response_to_text(
val.type=BINRPC_T_ALL;
val.name.s=0;
val.name.len=0;
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
if (ret < 0) {
if (ret == E_BINRPC_EOP) {
printf("end of message detected\n");

@ -199,6 +199,10 @@ int db_bind_mod(const str* mod, db_func_t* mydbf)
tmp = name;
}
if (!find_module_by_name(tmp)) {
LM_ERR("Module %s not found. Missing loadmodule? \n", tmp);
goto error;
}
dbind = (db_bind_api_f)find_mod_export(tmp, "db_bind_api", 0, 0);
if(dbind != NULL)
{

@ -44,6 +44,7 @@ int db_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l,
const unsigned int _cpy)
{
static str dummy_string = {"", 0};
static char dummy_string_buf[2];
if (!_v) {
LM_ERR("invalid parameter value\n");
@ -57,6 +58,8 @@ int db_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l,
* string so that we do not crash when the NULL flag
* is set but the module does not check it properly
*/
dummy_string_buf[0] = '\0';
dummy_string.s = dummy_string_buf;
VAL_STRING(_v) = dummy_string.s;
VAL_STR(_v) = dummy_string;
VAL_BLOB(_v) = dummy_string;

@ -152,6 +152,7 @@ int dtrie_insert(struct dtrie_node_t *root, const char *number, const unsigned i
if(node->child[digit]->child == NULL){
SHM_MEM_ERROR;
shm_free(node->child[digit]);
node->child[digit] = NULL;
return -1;
}
LM_DBG("allocate %lu bytes for %d root children pointer at %p\n",

@ -1793,6 +1793,7 @@ int main(int argc, char** argv)
int dont_fork_cnt;
struct name_lst* n_lst;
char *p;
struct stat st = {0};
/*init*/
time(&up_since);
@ -2312,6 +2313,19 @@ try_again:
}
sock_gid = gid;
}
/* create runtime dir if doesn't exist */
if (stat(runtime_dir, &st) == -1) {
if(mkdir(runtime_dir, 0700) == -1) {
fprintf(stderr, "failed to create runtime dir\n");
goto error;
}
if(sock_uid!=-1 || sock_gid!=-1) {
if(chown(runtime_dir, sock_uid, sock_gid) == -1) {
fprintf(stderr, "failed to change owner of runtime dir\n");
goto error;
}
}
}
if (fix_all_socket_lists()!=0){
fprintf(stderr, "failed to initialize list addresses\n");
goto error;

@ -91,6 +91,7 @@
((qm)->free_bitmap[(b)/FM_HASH_BMP_BITS] & (1UL<<((b)%FM_HASH_BMP_BITS)))
#define fm_is_free(f) ((f)->is_free)
/**
* \brief Find the first free fragment in a memory block
@ -158,12 +159,10 @@ inline static int fm_bmp_first_set(struct fm_block* qm, int start)
* \name Memory manager boundary check pattern
*/
/*@{ */
#ifdef DBG_F_MALLOC
#define ST_CHECK_PATTERN 0xf0f0f0f0 /** inserted at the beginning */
#define END_CHECK_PATTERN1 0xc0c0c0c0 /** inserted at the end */
#define END_CHECK_PATTERN2 0xabcdefed /** inserted at the end */
/*@} */
#endif
/**
@ -173,15 +172,22 @@ inline static int fm_bmp_first_set(struct fm_block* qm, int start)
*/
static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)
{
struct fm_frag** pf;
int hash;
pf = frag->prv_free;
hash = GET_HASH(frag->size);
*pf=frag->u.nxt_free;
if(frag->prev_free) {
frag->prev_free->next_free = frag->next_free;
} else {
qm->free_hash[hash].first = frag->next_free;
}
if(frag->next_free) {
frag->next_free->prev_free = frag->prev_free;
}
if(frag->u.nxt_free) frag->u.nxt_free->prv_free = pf;
frag->prev_free = NULL;
frag->next_free = NULL;
frag->is_free = 0;
qm->ffrags--;
qm->free_hash[hash].no--;
@ -189,7 +195,6 @@ static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)
if (qm->free_hash[hash].no==0)
fm_bmp_reset(qm, hash);
#endif /* F_MALLOC_HASH_BITMAP */
frag->prv_free = NULL;
qm->real_used+=frag->size;
qm->used+=frag->size;
@ -202,24 +207,42 @@ static inline void fm_extract_free(struct fm_block* qm, struct fm_frag* frag)
*/
static inline void fm_insert_free(struct fm_block* qm, struct fm_frag* frag)
{
struct fm_frag** f;
struct fm_frag* f;
struct fm_frag* p;
int hash;
hash=GET_HASH(frag->size);
f=&(qm->free_hash[hash].first);
f=qm->free_hash[hash].first;
p=NULL;
if (frag->size > F_MALLOC_OPTIMIZE){ /* because of '<=' in GET_HASH,
(different from 0.8.1[24] on
purpose --andrei ) */
for(; *f; f=&((*f)->u.nxt_free)){
if (frag->size <= (*f)->size) break;
/* large fragments list -- add at a position ordered by size */
for(; f; f=f->next_free){
if (frag->size <= f->size) break;
p = f;
}
}
/*insert it here*/
frag->prv_free = f;
frag->u.nxt_free=*f;
if (*f) (*f)->prv_free = &(frag->u.nxt_free);
*f=frag;
frag->next_free = f;
frag->prev_free = p;
if(f) {
f->prev_free = frag;
}
if(p) {
p->next_free = frag;
} else {
qm->free_hash[hash].first = frag;
}
} else {
/* fixed fragment size list -- add first */
frag->prev_free = 0;
frag->next_free = f;
if(f) {
f->prev_free = frag;
}
qm->free_hash[hash].first = frag;
}
frag->is_free = 1;
qm->ffrags++;
qm->free_hash[hash].no++;
#ifdef F_MALLOC_HASH_BITMAP
@ -268,8 +291,8 @@ void fm_split_frag(struct fm_block* qm, struct fm_frag* frag,
n->file=file;
n->func="frag. from fm_split_frag";
n->line=line;
n->check=ST_CHECK_PATTERN;
#endif
n->check=ST_CHECK_PATTERN;
/* reinsert n in free list*/
qm->used-=FRAG_OVERHEAD;
fm_insert_free(qm, n);
@ -327,15 +350,17 @@ struct fm_block* fm_malloc_init(char* address, unsigned long size, int type)
qm->last_frag=(struct fm_frag*)(end-sizeof(struct fm_frag));
/* init first fragment*/
qm->first_frag->size=size;
qm->first_frag->prv_free=0;
qm->first_frag->prev_free=0;
qm->first_frag->next_free=0;
qm->first_frag->is_free=0;
/* init last fragment*/
qm->last_frag->size=0;
qm->last_frag->prv_free=0;
qm->last_frag->prev_free=0;
qm->last_frag->next_free=0;
qm->last_frag->is_free=0;
#ifdef DBG_F_MALLOC
qm->first_frag->check=ST_CHECK_PATTERN;
qm->last_frag->check=END_CHECK_PATTERN1;
#endif
/* link initial fragment into the free list*/
@ -359,22 +384,23 @@ struct fm_frag* fm_search_defrag(struct fm_block* qm, unsigned long size)
while((char*)frag < (char*)qm->last_frag) {
nxt = FRAG_NEXT(frag);
if ( ((char*)nxt < (char*)qm->last_frag) && frag->prv_free
&& nxt->prv_free) {
/* join frag + nxt */
if ( ((char*)nxt < (char*)qm->last_frag) && fm_is_free(frag)
&& fm_is_free(nxt)) {
/* join frag with all next consecutive free frags */
fm_extract_free(qm, frag);
do {
fm_extract_free(qm, nxt);
frag->size += nxt->size + FRAG_OVERHEAD;
/* join - one frag less, add overhead to used */
/* after join - one frag less, add its overhead to used
* (real_used already has it - f and n were extracted */
qm->used += FRAG_OVERHEAD;
if( frag->size >size )
return frag;
nxt = FRAG_NEXT(frag);
} while (((char*)nxt < (char*)qm->last_frag) && nxt->prv_free);
} while (((char*)nxt < (char*)qm->last_frag) && fm_is_free(nxt));
fm_insert_free(qm, frag);
}
@ -399,7 +425,7 @@ void* fm_malloc(struct fm_block* qm, unsigned long size,
void* fm_malloc(struct fm_block* qm, unsigned long size)
#endif
{
struct fm_frag** f;
struct fm_frag* f;
struct fm_frag* frag;
int hash;
@ -418,8 +444,8 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
hash=fm_bmp_first_set(qm, GET_HASH(size));
if (likely(hash>=0)){
if (likely(hash<=F_MALLOC_OPTIMIZE/ROUNDTO)) { /* return first match */
f=&(qm->free_hash[hash].first);
if(likely(*f)) goto found;
f=qm->free_hash[hash].first;
if(likely(f)) goto found;
#ifdef DBG_F_MALLOC
MDBG(" block %p hash %d empty but no. is %lu\n", qm,
hash, qm->free_hash[hash].no);
@ -437,17 +463,17 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
hash buckets.
*/
do {
for(f=&(qm->free_hash[hash].first);(*f); f=&((*f)->u.nxt_free))
if ((*f)->size>=size) goto found;
for(f=qm->free_hash[hash].first; f; f=f->next_free)
if (f->size>=size) goto found;
hash++; /* try in next hash cell */
}while((hash < F_HASH_SIZE) &&
((hash=fm_bmp_first_set(qm, hash)) >= 0));
}
#else /* F_MALLOC_HASH_BITMAP */
for(hash=GET_HASH(size);hash<F_HASH_SIZE;hash++){
f=&(qm->free_hash[hash].first);
for(;(*f); f=&((*f)->u.nxt_free))
if ((*f)->size>=size) goto found;
f=qm->free_hash[hash].first;
for(; f; f=f->u.nxt_free)
if (f->size>=size) goto found;
/* try in a bigger bucket */
}
#endif /* F_MALLOC_HASH_BITMAP */
@ -462,7 +488,7 @@ void* fm_malloc(struct fm_block* qm, unsigned long size)
found:
/* we found it!*/
/* detach it from the free list*/
frag=*f;
frag=f;
fm_extract_free(qm, frag);
/*see if use full frag or split it in two*/
@ -478,10 +504,10 @@ finish:
frag->file=file;
frag->func=func;
frag->line=line;
frag->check=ST_CHECK_PATTERN;
MDBG("fm_malloc(%p, %lu) returns address %p \n", qm, size,
(char*)frag+sizeof(struct fm_frag));
#endif
frag->check=ST_CHECK_PATTERN;
if (qm->max_real_used<qm->real_used)
qm->max_real_used=qm->real_used;
@ -495,40 +521,28 @@ finish:
#ifdef MEM_JOIN_FREE
/**
* join fragment f with next one (if it is free)
* join fragment free frag f with next one (if it is free)
*/
static void fm_join_frag(struct fm_block* qm, struct fm_frag* f)
{
int hash;
struct fm_frag **pf;
struct fm_frag* n;
struct fm_frag *n;
n=FRAG_NEXT(f);
/* check if valid and if in free list */
if (((char*)n >= (char*)qm->last_frag) || (n->prv_free==NULL))
/* check if n is valid and if in free list */
if (((char*)n >= (char*)qm->last_frag) || !fm_is_free(n))
return;
/* detach n from the free list */
hash=GET_HASH(n->size);
pf=n->prv_free;
if (*pf==0){
/* not found, bad! */
LM_WARN("could not find %p in free list (hash=%ld)\n", n, GET_HASH(n->size));
return;
}
/* detach */
*pf=n->u.nxt_free;
if(n->u.nxt_free) n->u.nxt_free->prv_free = pf;
qm->ffrags--;
qm->free_hash[hash].no--;
#ifdef F_MALLOC_HASH_BITMAP
if (qm->free_hash[hash].no==0)
fm_bmp_reset(qm, hash);
#endif /* F_MALLOC_HASH_BITMAP */
/* join */
fm_extract_free(qm, n);
/* join - f extended with size of n plus its overhead */
f->size+=n->size+FRAG_OVERHEAD;
qm->real_used+=n->size;
qm->used+=n->size + FRAG_OVERHEAD;
/* after join - one frag less, add its overhead to used
* (real_used already has it - f and n were extracted */
qm->used += FRAG_OVERHEAD;
}
#endif /*MEM_JOIN_FREE*/
@ -570,7 +584,7 @@ void fm_free(struct fm_block* qm, void* p)
MDBG("fm_free: freeing block alloc'ed from %s: %s(%ld)\n",
f->file, f->func, f->line);
#endif
if(unlikely(f->prv_free!=NULL)) {
if(unlikely(fm_is_free(f))) {
LM_INFO("freeing a free fragment (%p/%p) - ignore\n",
f, p);
return;
@ -659,11 +673,12 @@ void* fm_realloc(struct fm_block* qm, void* p, unsigned long size)
#endif
diff=size-f->size;
n=FRAG_NEXT(f);
/*if next frag is free, check if a join has enough size*/
if (((char*)n < (char*)qm->last_frag) &&
(n->prv_free) && ((n->size+FRAG_OVERHEAD)>=diff)){
fm_is_free(n) && ((n->size+FRAG_OVERHEAD)>=diff)){
/* detach n from the free list */
fm_extract_free(qm, n);
/* join */
/* join */
f->size+=n->size+FRAG_OVERHEAD;
qm->used+=FRAG_OVERHEAD;
@ -761,7 +776,7 @@ void fm_status(struct fm_block* qm)
for(h=0,i=0,size=0;h<F_HASH_SIZE;h++){
unused=0;
for (f=qm->free_hash[h].first,j=0; f;
size+=f->size,f=f->u.nxt_free,i++,j++){
size+=f->size,f=f->next_free,i++,j++){
if (!FRAG_WAS_USED(f)){
unused++;
#ifdef DBG_F_MALLOC
@ -892,7 +907,7 @@ void fm_sums(struct fm_block* qm)
for (f=qm->first_frag, i=0; (char*)f<(char*)qm->last_frag;
f=FRAG_NEXT(f), i++){
if (f->prv_free==0){
if (!fm_is_free(f)){
x = get_mem_counter(&root,f);
x->count++;
x->size+=f->size;

@ -80,18 +80,16 @@ typedef unsigned long fm_hash_bitmap_t;
* - +1 .... end - size = 2^k, big buckets
*/
struct fm_frag{
unsigned long size;
union{
struct fm_frag* nxt_free;
long reserved;
}u;
struct fm_frag** prv_free;
unsigned long size; /* size of fragment */
struct fm_frag* next_free; /* next free frag in slot */
struct fm_frag* prev_free; /* prev free frag in slot - for faster join/defrag */
unsigned int is_free; /* used to detect if fragment is free (when not 0) */
#ifdef DBG_F_MALLOC
const char* file;
const char* func;
unsigned long line;
unsigned long check;
#endif
unsigned int check;
};
struct fm_frag_lnk{

@ -767,7 +767,8 @@ modparam("acc", "failed_filter", "404,407")
Shall acc attempt to account e2e ACKs too ? Note that this is really
only an attempt, as e2e ACKs may take a different path (unless RR
enabled) and mismatch original INVITE (e2e ACKs are a separate
transaction).
transaction). The flag for accounting has to be set for each ACK as
well.
Default value is 0 (no).

@ -615,7 +615,7 @@ static inline void acc_onack( struct cell* t, struct sip_msg *req,
#endif
/* run extra acc engines */
acc_run_engines(req, 0, NULL);
acc_run_engines(ack, 0, NULL);
}

@ -559,7 +559,8 @@ modparam("acc", "failed_filter", "404,407")
Shall acc attempt to account e2e ACKs too ? Note that this is really
only an attempt, as e2e ACKs may take a different path
(unless RR enabled) and mismatch original INVITE (e2e ACKs are
a separate transaction).
a separate transaction). The flag for accounting has to be set
for each ACK as well.
</para>
<para>
Default value is 0 (no).

@ -1,6 +1,4 @@
/*
* $Id$
*
* Accounting module
*
* Copyright (C) 2001-2003 FhG Fokus
@ -21,9 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* History:
* -------
* 2010-07-28 - moved out radius account out of acc module (daniel)
*/
/*! \file
@ -49,6 +44,7 @@
#include "../../lib/kcore/radius.h"
#include "../../modules/acc/acc_api.h"
#include "acc_radius_mod.h"
#include "../../modules/acc/acc_extra.h"
MODULE_VERSION
@ -129,7 +125,7 @@ static int mod_init( void )
LM_ERR("radius config file not set\n");
return -1;
}
/* bind the ACC API */
if (acc_load_api(&accb)<0) {
LM_ERR("cannot bind to ACC API\n");
@ -141,7 +137,7 @@ static int mod_init( void )
LM_ERR("failed to parse rad_extra param\n");
return -1;
}
memset(&_acc_radius_engine, 0, sizeof(acc_engine_t));
if(radius_flag != -1)
@ -196,7 +192,7 @@ static int acc_api_fixup(void** param, int param_no)
accp->reason.len = strlen(p);
/* any code? */
if (accp->reason.len>=3 && isdigit((int)p[0])
&& isdigit((int)p[1]) && isdigit((int)p[2]) ) {
&& isdigit((int)p[1]) && isdigit((int)p[2]) ) {
accp->code = (p[0]-'0')*100 + (p[1]-'0')*10 + (p[2]-'0');
accp->code_s.s = p;
accp->code_s.len = 3;
@ -233,7 +229,7 @@ enum { RA_ACCT_STATUS_TYPE=0, RA_SERVICE_TYPE, RA_SIP_RESPONSE_CODE,
enum {RV_STATUS_START=0, RV_STATUS_STOP, RV_STATUS_ALIVE, RV_STATUS_FAILED,
RV_SIP_SESSION, RV_STATIC_MAX};
static struct attr
rd_attrs[RA_STATIC_MAX+ACC_CORE_LEN-2+MAX_ACC_EXTRA+MAX_ACC_LEG];
rd_attrs[RA_STATIC_MAX+ACC_CORE_LEN-2+MAX_ACC_EXTRA+MAX_ACC_LEG];
static struct val rd_vals[RV_STATIC_MAX];
int init_acc_rad(acc_extra_t *leg_info, char *rad_cfg, int srv_type)
@ -297,30 +293,30 @@ int acc_radius_init(acc_init_info_t *inf)
static inline uint32_t rad_status( struct sip_msg *req, int code )
{
str tag;
unsigned int in_dialog_req = 0;
str tag;
unsigned int in_dialog_req = 0;
tag = get_to(req)->tag_value;
if(tag.s!=0 && tag.len!=0)
tag = get_to(req)->tag_value;
if(tag.s!=0 && tag.len!=0)
in_dialog_req = 1;
if (req->REQ_METHOD==METHOD_INVITE && in_dialog_req == 0
&& code>=200 && code<300)
return rd_vals[RV_STATUS_START].v;
if ((req->REQ_METHOD==METHOD_BYE || req->REQ_METHOD==METHOD_CANCEL))
return rd_vals[RV_STATUS_STOP].v;
&& code>=200 && code<300)
return rd_vals[RV_STATUS_START].v;
if ((req->REQ_METHOD==METHOD_BYE || req->REQ_METHOD==METHOD_CANCEL))
return rd_vals[RV_STATUS_STOP].v;
if (in_dialog_req != 0)
return rd_vals[RV_STATUS_ALIVE].v;
return rd_vals[RV_STATUS_FAILED].v;
}
return rd_vals[RV_STATUS_FAILED].v;
}
#define ADD_RAD_AVPAIR(_attr,_val,_len) \
do { \
if (!rc_avpair_add(rh, &send, rd_attrs[_attr].v, _val, _len, 0)) { \
LM_ERR("failed to add %s, %d\n", rd_attrs[_attr].n, _attr); \
goto error; \
} \
}while(0)
do { \
if (!rc_avpair_add(rh, &send, rd_attrs[_attr].v, _val, _len, 0)) { \
LM_ERR("failed to add %s, %d\n", rd_attrs[_attr].n, _attr); \
goto error; \
} \
}while(0)
int acc_radius_send_request(struct sip_msg *req, acc_info_t *inf)
{
@ -329,6 +325,8 @@ int acc_radius_send_request(struct sip_msg *req, acc_info_t *inf)
uint32_t av_type;
int offset;
int i;
int m=0;
int o=0;
send=NULL;
@ -353,23 +351,26 @@ int acc_radius_send_request(struct sip_msg *req, acc_info_t *inf)
ADD_RAD_AVPAIR( RA_TIME_STAMP, &av_type, -1);
/* add extra also */
attr_cnt += accb.get_extra_attrs(rad_extra, req, inf->varr+attr_cnt,
inf->iarr+attr_cnt, inf->tarr+attr_cnt);
o = accb.get_extra_attrs(rad_extra, req, inf->varr+attr_cnt,
inf->iarr+attr_cnt, inf->tarr+attr_cnt);
attr_cnt += o;
m = attr_cnt;
/* add the values for the vector - start from 1 instead of
* 0 to skip the first value which is the METHOD as string */
offset = RA_STATIC_MAX-1;
for( i=1; i<attr_cnt; i++) {
switch (inf->tarr[i]) {
case TYPE_STR:
ADD_RAD_AVPAIR(offset+i, inf->varr[i].s, inf->varr[i].len);
break;
case TYPE_INT:
ADD_RAD_AVPAIR(offset+i, &(inf->iarr[i]), -1);
break;
default:
break;
}
switch (inf->tarr[i]) {
case TYPE_STR:
ADD_RAD_AVPAIR(offset+i, inf->varr[i].s, inf->varr[i].len);
break;
case TYPE_INT:
ADD_RAD_AVPAIR(offset+i, &(inf->iarr[i]), -1);
break;
default:
break;
}
}
/* call-legs attributes also get inserted */
@ -380,7 +381,7 @@ int acc_radius_send_request(struct sip_msg *req, acc_info_t *inf)
for (i=0; i<attr_cnt; i++)
ADD_RAD_AVPAIR( offset+i, inf->varr[i].s, inf->varr[i].len );
}while ( (attr_cnt=accb.get_leg_attrs(inf->leg_info,req,inf->varr,inf->iarr,
inf->tarr, 0))!=0 );
inf->tarr, 0))!=0 );
}
if (rc_acct(rh, SIP_PORT, send)!=OK_RC) {
@ -388,10 +389,14 @@ int acc_radius_send_request(struct sip_msg *req, acc_info_t *inf)
goto error;
}
rc_avpair_free(send);
/* free memory allocated by extra2strar */
free_strar_mem( &(inf->tarr[m-o]), &(inf->varr[m-o]), o, m);
return 1;
error:
rc_avpair_free(send);
/* free memory allocated by extra2strar */
free_strar_mem( &(inf->tarr[m-o]), &(inf->varr[m-o]), o, m);
return -1;
}

@ -167,7 +167,7 @@ static mi_export_t mi_cmds[] = {
/*
* Module interface
*/
struct module_exports exports = {
struct module_exports _app_perl_exports = {
"app_perl",
RTLD_NOW | RTLD_GLOBAL,
cmds, /* Exported functions */
@ -351,7 +351,7 @@ static int mod_init(void) {
struct timeval t1;
struct timeval t2;
if(register_mi_mod(exports.name, mi_cmds)!=0)
if(register_mi_mod(_app_perl_exports.name, mi_cmds)!=0)
{
LM_ERR("failed to register MI commands\n");
return -1;

@ -94,7 +94,7 @@ static int mod_init(void)
{
if (load_tm_api( &tmb ) == -1)
{
LM_ERR("cannot load the TM-functions\n");
LM_ERR("cannot load the TM-functions. Missing TM module?\n");
return -1;
}
@ -151,7 +151,7 @@ static int w_async_sleep(struct sip_msg* msg, char* sec, char* str2)
if(async_workers<=0)
{
LM_ERR("no async mod timer wokers\n");
LM_ERR("no async mod timer workers (modparam missing?)\n");
return -1;
}
@ -188,7 +188,7 @@ static int fixup_async_sleep(void** param, int param_no)
ap = (async_param_t*)pkg_malloc(sizeof(async_param_t));
if(ap==NULL)
{
LM_ERR("no more pkg\n");
LM_ERR("no more pkg memory available\n");
return -1;
}
memset(ap, 0, sizeof(async_param_t));
@ -215,7 +215,7 @@ static int w_async_route(struct sip_msg* msg, char* rt, char* sec)
if(async_workers<=0)
{
LM_ERR("no async mod timer wokers\n");
LM_ERR("no async mod timer workers\n");
return -1;
}

@ -141,7 +141,7 @@ int async_sleep(struct sip_msg* msg, int seconds, cfg_action_t *act)
ai = (async_item_t*)shm_malloc(sizeof(async_item_t));
if(ai==NULL)
{
LM_ERR("no more shm\n");
LM_ERR("no more shm memory\n");
return -1;
}
memset(ai, 0, sizeof(async_item_t));
@ -149,7 +149,7 @@ int async_sleep(struct sip_msg* msg, int seconds, cfg_action_t *act)
ai->act = act;
if(tmb.t_suspend(msg, &ai->tindex, &ai->tlabel)<0)
{
LM_ERR("failed to suppend the processing\n");
LM_ERR("failed to suspend the processing\n");
shm_free(ai);
return -1;
}
@ -239,13 +239,13 @@ int async_send_task(sip_msg_t* msg, cfg_action_t *act)
at = (async_task_t*)shm_malloc(dsize);
if(at==NULL)
{
LM_ERR("no more shm\n");
LM_ERR("no more shm memory\n");
return -1;
}
memset(at, 0, dsize);
if(tmb.t_suspend(msg, &tindex, &tlabel)<0)
{
LM_ERR("failed to suppend the processing\n");
LM_ERR("failed to suspend the processing\n");
shm_free(at);
return -1;
}

@ -15,46 +15,46 @@ Daniel-Constantin Mierla
asipto.com
<miconda@gmail.com>
Copyright © 2002, 2003 FhG FOKUS
Copyright © 2002, 2003 FhG FOKUS
__________________________________________________________________
Table of Contents
1. Admin Guide
1.1. Overview
1.2. Dependencies
1.3. Parameters
1.3.1. auth_checks_register (flags)
1.3.2. auth_checks_no_dlg (flags)
1.3.3. auth_checks_in_dlg (flags)
1.3.4. qop (string)
1.3.5. nonce_count (boolean)
1.3.6. one_time_nonce (boolean)
1.3.7. nid_pool_no (integer)
1.3.8. nc_array_size (integer)
1.3.9. nc_array_order (integer)
1.3.10. otn_in_flight_no (integer)
1.3.11. otn_in_flight_order (integer)
1.3.12. secret (string)
1.3.13. nonce_expire (integer)
1.3.14. nonce_auth_max_drift (integer)
1.3.15. force_stateless_reply (boolean)
1.3.16. realm_prefix (string)
1.3.17. use_domain (boolean)
1.4. Functions
1.4.1. consume_credentials()
1.4.2. has_credentials(realm)
1.4.3. www_challenge(realm, flags)
1.4.4. proxy_challenge(realm, flags)
1.4.5. auth_challenge(realm, flags)
1.4.6. pv_www_authenticate(realm, passwd, flags [, method])
1.4.7. pv_proxy_authenticate(realm, passwd, flags)
1.4.8. pv_auth_check(realm, passwd, flags, checks)
1.4.9. auth_get_www_authenticate(realm, flags, pvdest)
1. Overview
2. Dependencies
3. Parameters
3.1. auth_checks_register (flags)
3.2. auth_checks_no_dlg (flags)
3.3. auth_checks_in_dlg (flags)
3.4. qop (string)
3.5. nonce_count (boolean)
3.6. one_time_nonce (boolean)
3.7. nid_pool_no (integer)
3.8. nc_array_size (integer)
3.9. nc_array_order (integer)
3.10. otn_in_flight_no (integer)
3.11. otn_in_flight_order (integer)
3.12. secret (string)
3.13. nonce_expire (integer)
3.14. nonce_auth_max_drift (integer)
3.15. force_stateless_reply (boolean)
3.16. realm_prefix (string)
3.17. use_domain (boolean)
4. Functions
4.1. consume_credentials()
4.2. has_credentials(realm)
4.3. www_challenge(realm, flags)
4.4. proxy_challenge(realm, flags)
4.5. auth_challenge(realm, flags)
4.6. pv_www_authenticate(realm, passwd, flags [, method])
4.7. pv_proxy_authenticate(realm, passwd, flags)
4.8. pv_auth_check(realm, passwd, flags, checks)
4.9. auth_get_www_authenticate(realm, flags, pvdest)
List of Examples
@ -85,7 +85,43 @@ Daniel-Constantin Mierla
Chapter 1. Admin Guide
1.1. Overview
Table of Contents
1. Overview
2. Dependencies
3. Parameters
3.1. auth_checks_register (flags)
3.2. auth_checks_no_dlg (flags)
3.3. auth_checks_in_dlg (flags)
3.4. qop (string)
3.5. nonce_count (boolean)
3.6. one_time_nonce (boolean)
3.7. nid_pool_no (integer)
3.8. nc_array_size (integer)
3.9. nc_array_order (integer)
3.10. otn_in_flight_no (integer)
3.11. otn_in_flight_order (integer)
3.12. secret (string)
3.13. nonce_expire (integer)
3.14. nonce_auth_max_drift (integer)
3.15. force_stateless_reply (boolean)
3.16. realm_prefix (string)
3.17. use_domain (boolean)
4. Functions
4.1. consume_credentials()
4.2. has_credentials(realm)
4.3. www_challenge(realm, flags)
4.4. proxy_challenge(realm, flags)
4.5. auth_challenge(realm, flags)
4.6. pv_www_authenticate(realm, passwd, flags [, method])
4.7. pv_proxy_authenticate(realm, passwd, flags)
4.8. pv_auth_check(realm, passwd, flags, checks)
4.9. auth_get_www_authenticate(realm, flags, pvdest)
1. Overview
This is a generic module that itself doesn't provide all functions
necessary for authentication but provides functions that are needed by
@ -99,21 +135,39 @@ Chapter 1. Admin Guide
functionality. This also allows us to avoid unnecessary dependencies in
the binary packages.
1.2. Dependencies
2. Dependencies
The module does not depend on any other module.
1.3. Parameters
1.3.1. auth_checks_register (flags)
3. Parameters
3.1. auth_checks_register (flags)
3.2. auth_checks_no_dlg (flags)
3.3. auth_checks_in_dlg (flags)
3.4. qop (string)
3.5. nonce_count (boolean)
3.6. one_time_nonce (boolean)
3.7. nid_pool_no (integer)
3.8. nc_array_size (integer)
3.9. nc_array_order (integer)
3.10. otn_in_flight_no (integer)
3.11. otn_in_flight_order (integer)
3.12. secret (string)
3.13. nonce_expire (integer)
3.14. nonce_auth_max_drift (integer)
3.15. force_stateless_reply (boolean)
3.16. realm_prefix (string)
3.17. use_domain (boolean)
3.1. auth_checks_register (flags)
See description of parameter auth_checks_in_dlg.
1.3.2. auth_checks_no_dlg (flags)
3.2. auth_checks_no_dlg (flags)
See description of parameter auth_checks_in_dlg.
1.3.3. auth_checks_in_dlg (flags)
3.3. auth_checks_in_dlg (flags)
These three module parameters control which optional integrity checks
will be performed on the SIP message carrying digest response during
@ -198,7 +252,7 @@ modparam("auth", "auth_checks_in_dlg", 15)
...
1.3.4. qop (string)
3.4. qop (string)
If set, enable qop for challenges: each challenge will include a qop
parameter. This is the recommended way, but some older non rfc3261
@ -220,7 +274,7 @@ modparam("auth", "auth_checks_in_dlg", 15)
modparam("auth", "qop", "auth") # set qop=auth
...
1.3.5. nonce_count (boolean)
3.5. nonce_count (boolean)
If enabled the received nc value is remembered and checked against the
older value (for a successful authentication the received nc must be
@ -316,7 +370,7 @@ route{
}
...
1.3.6. one_time_nonce (boolean)
3.6. one_time_nonce (boolean)
If set to 1 nonce reuse is disabled: each nonce is allowed only once,
in the first reponse to a challenge. All the messages will be
@ -360,7 +414,7 @@ modparam("auth", "one_time_nonce", 1)
# Note: stateful mode should be used, see the nonce_count example
...
1.3.7. nid_pool_no (integer)
3.7. nid_pool_no (integer)
Controls the number of partitions for the nonce_count and
one_time_nonce arrays (it's common to both of them to reduce the nonce
@ -396,7 +450,7 @@ modparam("auth", "one_time_nonce", 1)
modparam("auth", "nid_pool_no", 4)
...
1.3.8. nc_array_size (integer)
3.8. nc_array_size (integer)
Maximum number of in-flight nonces for nonce_count. It represents the
maximum nonces for which state will be kept. When this number is
@ -420,7 +474,7 @@ modparam("auth", "nid_pool_no", 4)
modparam("auth", "nc_array_size", 4194304) # 4Mb
...
1.3.9. nc_array_order (integer)
3.9. nc_array_order (integer)
Equivalent to nc_array_size, but instead of directly specifying the
size, its value is the power at which 2 should be raised
@ -437,7 +491,7 @@ modparam("auth", "nc_array_size", 4194304) # 4Mb
modparam("auth", "nc_array_order", 22) # 4Mb
...
1.3.10. otn_in_flight_no (integer)
3.10. otn_in_flight_no (integer)
Maximum number of in-flight nonces for one_time_nonce. It represents
the maximum number of nonces remembered for the one-time-nonce check.
@ -463,7 +517,7 @@ modparam("auth", "nc_array_order", 22) # 4Mb
modparam("auth", "otn_in_flight_no", 8388608) # 8 Mb (1Mb memory)
...
1.3.11. otn_in_flight_order (integer)
3.11. otn_in_flight_order (integer)
Equivalent to otn_in_flight_no, but instead of directly specifying the
size, its value is the power at which 2 should be raised
@ -481,7 +535,7 @@ modparam("auth", "otn_in_flight_no", 8388608) # 8 Mb (1Mb memory)
modparam("auth", "otn_in_flight_order", 23) # 8 Mb (1Mb memory)
...
1.3.12. secret (string)
3.12. secret (string)
Secret phrase used to calculate the nonce value used to challenge the
client for authentication.
@ -501,7 +555,7 @@ modparam("auth", "otn_in_flight_order", 23) # 8 Mb (1Mb memory)
modparam("auth", "secret", "johndoessecretphrase")
...
1.3.13. nonce_expire (integer)
3.13. nonce_expire (integer)
Nonces have limited lifetime. After a given period of time nonces will
be considered invalid. This is to protect replay attacks. Credentials
@ -518,7 +572,7 @@ modparam("auth", "secret", "johndoessecretphrase")
modparam("auth", "nonce_expire", 600) # Set nonce_expire to 600s
...
1.3.14. nonce_auth_max_drift (integer)
3.14. nonce_auth_max_drift (integer)
Maximum difference in seconds between a nonce creation time and the
current time, if the nonce creation time appears to be in the future.
@ -540,7 +594,7 @@ modparam("auth", "nonce_expire", 600) # Set nonce_expire to 600s
modparam("auth", "nonce_auth_max_drift", 1) # set max drift to 1 s
...
1.3.15. force_stateless_reply (boolean)
3.15. force_stateless_reply (boolean)
If set to 1, www_challenge() and proxy_challenge() functions send reply
statelessly no matter if transaction exists or not. If set to 0
@ -552,13 +606,13 @@ modparam("auth", "nonce_auth_max_drift", 1) # set max drift to 1 s
modparam("auth", "force_stateless_reply", 1)
...
1.3.16. realm_prefix (string)
3.16. realm_prefix (string)
Prefix to be automatically strip from realm. As an alternative to SRV
records (not all SIP clients support SRV lookup), a subdomain of the
master domain can be defined for SIP purposes (like sip.mydomain.net
pointing to same IP address as the SRV record for mydomain.net). By
ignoring the realm_prefix “sip.”, at authentication, sip.mydomain.net
ignoring the realm_prefix "sip.", at authentication, sip.mydomain.net
will be equivalent to mydomain.net .
Default value is empty string.
@ -566,7 +620,7 @@ modparam("auth", "force_stateless_reply", 1)
Example 1.14. realm_prefix parameter example
modparam("auth", "realm_prefix", "sip.")
1.3.17. use_domain (boolean)
3.17. use_domain (boolean)
If set to 1, pv_auth_check() uses domain parts of the URIs to check
user identity.
@ -576,9 +630,19 @@ modparam("auth", "realm_prefix", "sip.")
modparam("auth", "use_domain", 1)
...
1.4. Functions
4. Functions
1.4.1. consume_credentials()
4.1. consume_credentials()
4.2. has_credentials(realm)
4.3. www_challenge(realm, flags)
4.4. proxy_challenge(realm, flags)
4.5. auth_challenge(realm, flags)
4.6. pv_www_authenticate(realm, passwd, flags [, method])
4.7. pv_proxy_authenticate(realm, passwd, flags)
4.8. pv_auth_check(realm, passwd, flags, checks)
4.9. auth_get_www_authenticate(realm, flags, pvdest)
4.1. consume_credentials()
This function removes previously authorized credential headers from the
message being processed by the server. That means that the downstream
@ -595,7 +659,7 @@ if (www_authenticate("realm", "subscriber")) {
};
...
1.4.2. has_credentials(realm)
4.2. has_credentials(realm)
This function returns true of the request has Autorization or
Proxy-Authorization header with provided realm. The parameter can be
@ -608,7 +672,7 @@ if (has_credentials("myrealm")) {
}
...
1.4.3. www_challenge(realm, flags)
4.3. www_challenge(realm, flags)
The function challenges a user agent. It will generate a WWW-Authorize
header field containing a digest challenge, it will put the header
@ -622,7 +686,7 @@ if (has_credentials("myrealm")) {
* realm - Realm is a opaque string that the user agent should present
to the user so he can decide what username and password to use.
Usually this is domain of the host the server is running on.
It must not be empty string “”. In case of REGISTER requests, the
It must not be empty string "". In case of REGISTER requests, the
To header field domain (e.g., variable $td) can be used (because
this header field represents the user being registered), for all
other messages From header field domain can be used (e.g., variable
@ -645,7 +709,7 @@ if (!www_authenticate("$td", "subscriber")) {
}
...
1.4.4. proxy_challenge(realm, flags)
4.4. proxy_challenge(realm, flags)
The function challenges a user agent. It will generate a
Proxy-Authorize header field containing a digest challenge, it will put
@ -667,7 +731,7 @@ if (!proxy_authenticate("$fd", "subscriber")) {
};
...
1.4.5. auth_challenge(realm, flags)
4.5. auth_challenge(realm, flags)
The function challenges a user agent for authentication. It combines
the functions www_challenge() and proxy_challenge(), by calling
@ -686,7 +750,7 @@ if (!auth_check("$fd", "subscriber", "1")) {
};
...
1.4.6. pv_www_authenticate(realm, passwd, flags [, method])
4.6. pv_www_authenticate(realm, passwd, flags [, method])
The function verifies credentials according to RFC2617. If the
credentials are verified successfully then the function will succeed
@ -699,20 +763,17 @@ if (!auth_check("$fd", "subscriber", "1")) {
* -1 (generic error) - some generic error occurred and no reply was
sent out
* -2 (invalid password) - wrong password
* -3 (invalid user) - authentication user does not exist
* -4 (nonce expired) - the nonce has expired
* -5 (no credentials) - request does not contain an Authorization
header with the correct realm
* -6 (nonce reused) - the nonce has already been used to authenticate
a previous request
* -8 (auth user mismatch) - the auth user is different then the
From/To user
Meaning of the parameters is as follows:
* realm - Realm is a opaque string that the user agent should present
to the user so he can decide what username and password to use.
Usually this is domain of the host the server is running on.
It must not be empty string “”. In case of REGISTER requests To
It must not be empty string "". In case of REGISTER requests To
header field domain (e.g., varibale $td) can be used (because this
header field represents a user being registered), for all other
messages From header field domain can be used (e.g., varibale $fd).
@ -741,7 +802,7 @@ if (!pv_www_authenticate("$td", "123abc", "0")) {
};
...
1.4.7. pv_proxy_authenticate(realm, passwd, flags)
4.7. pv_proxy_authenticate(realm, passwd, flags)
The function verifies credentials according to RFC2617. If the
credentials are verified successfully then the function will succeed
@ -764,7 +825,7 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
};
...
1.4.8. pv_auth_check(realm, passwd, flags, checks)
4.8. pv_auth_check(realm, passwd, flags, checks)
The function combines the functionalities of pv_www_authenticate and
pv_proxy_authenticate, first being exectuted if the SIP request is a
@ -779,6 +840,12 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
it is for a REGISTER request or not. The parameter may be a pseudo
variable.
The set of possible return codes is the same than
pv_{www,proxy}_authenticate, with one more possible value:
-8 (auth user mismatch) - the auth user is different than the From/To
user
This function can be used from REQUEST_ROUTE.
Example 1.23. pv_auth_check usage
@ -789,7 +856,7 @@ if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) {
};
...
1.4.9. auth_get_www_authenticate(realm, flags, pvdest)
4.9. auth_get_www_authenticate(realm, flags, pvdest)
Build WWW-Authentication header and set the resulting value in 'pvdest'
pseudo-variable parameter.

@ -204,10 +204,6 @@ if (!auth_check("$fd", "subscriber", "1")) {
<emphasis>-2 (invalid password)</emphasis> - wrong password
</para></listitem>
<listitem><para>
<emphasis>-3 (invalid user)</emphasis> - authentication user does
not exist
</para></listitem>
<listitem><para>
<emphasis>-4 (nonce expired)</emphasis> - the nonce has expired
</para></listitem>
<listitem><para>
@ -218,10 +214,6 @@ if (!auth_check("$fd", "subscriber", "1")) {
<emphasis>-6 (nonce reused)</emphasis> - the nonce has already been
used to authenticate a previous request
</para></listitem>
<listitem><para>
<emphasis>-8 (auth user mismatch)</emphasis> - the auth user is different
then the From/To user
</para></listitem>
</itemizedlist>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
@ -357,6 +349,13 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
request or not. The parameter may be a pseudo variable.
</para>
<para>
The set of possible return codes is the same than pv_{www,proxy}_authenticate, with
one more possible value:
<para><emphasis>-8 (auth user mismatch)</emphasis> - the auth user is different
than the From/To user
</para>
</para>
<para>
This function can be used from REQUEST_ROUTE.
</para>
<example>

@ -357,7 +357,13 @@ int check_nonce(auth_body_t* auth, str* secret1, str* secret2,
different length (for example because of different auth.
checks).. Therefore we force credentials to be rebuilt by UAC
without prompting for password */
return 4;
/* if current time is less than start time, reset the start time
* (e.g., after start, the system clock was set in the past) */
t=time(0);
if (t < up_since)
up_since = t;
if (since < t)
return 4;
}
t=time(0);
if (unlikely((since > t) && ((since-t) > nonce_auth_max_drift) )){

@ -512,30 +512,40 @@ int auth_check(struct sip_msg* _m, char* _realm, char* _table, char *_flags)
|| _m->REQ_METHOD==METHOD_PRACK || _m->REQ_METHOD==METHOD_UPDATE
|| _m->REQ_METHOD==METHOD_MESSAGE))) {
if(srealm.len!=uri->user.len
|| strncmp(srealm.s, uri->user.s, srealm.len)!=0)
|| strncmp(srealm.s, uri->user.s, srealm.len)!=0) {
LM_DBG("authentication username mismatch with from/to username\n");
return AUTH_USER_MISMATCH;
}
}
if(_m->REQ_METHOD==METHOD_REGISTER || _m->REQ_METHOD==METHOD_PUBLISH) {
/* check from==to */
if(furi->user.len!=turi->user.len
|| strncmp(furi->user.s, turi->user.s, furi->user.len)!=0)
|| strncmp(furi->user.s, turi->user.s, furi->user.len)!=0) {
LM_DBG("from username mismatch with to username\n");
return AUTH_USER_MISMATCH;
}
if(use_domain!=0 && (furi->host.len!=turi->host.len
|| strncmp(furi->host.s, turi->host.s, furi->host.len)!=0))
|| strncmp(furi->host.s, turi->host.s, furi->host.len)!=0)) {
LM_DBG("from domain mismatch with to domain\n");
return AUTH_USER_MISMATCH;
}
/* check r-uri==from for publish */
if(_m->REQ_METHOD==METHOD_PUBLISH) {
if(parse_sip_msg_uri(_m)<0)
return AUTH_ERROR;
uri = &_m->parsed_uri;
if(furi->user.len!=uri->user.len
|| strncmp(furi->user.s, uri->user.s, furi->user.len)!=0)
|| strncmp(furi->user.s, uri->user.s, furi->user.len)!=0) {
LM_DBG("from username mismatch with r-uri username\n");
return AUTH_USER_MISMATCH;
}
if(use_domain!=0 && (furi->host.len!=uri->host.len
|| strncmp(furi->host.s, uri->host.s, furi->host.len)!=0))
|| strncmp(furi->host.s, uri->host.s, furi->host.len)!=0)) {
LM_DBG("from domain mismatch with r-uri domain\n");
return AUTH_USER_MISMATCH;
}
}
}
return AUTH_OK;
}

@ -118,7 +118,7 @@ static int __add_call_by_cid(str *cid, call_t *call, credit_type_t type);
static call_t *__alloc_new_call_by_time(credit_data_t *credit_data, struct sip_msg *msg, int max_secs);
static call_t *__alloc_new_call_by_money(credit_data_t *credit_data, struct sip_msg *msg, double credit,
double cost_per_second, int initial_pulse, int final_pulse);
static void __notify_call_termination(sip_data_t *data);
static void __notify_call_termination(sip_msg_t *msg);
static void __free_call(call_t *call);
static int __has_to_tag(struct sip_msg *msg);
static credit_data_t *__alloc_new_credit_data(str *client_id, credit_type_t type);
@ -454,18 +454,8 @@ static void __dialog_terminated_callback(struct dlg_cell *cell, int type, struct
__stop_billing(&cell->callid);
}
static void __notify_call_termination(sip_data_t *data) {
static void __notify_call_termination(sip_msg_t *msg) {
struct run_act_ctx ra_ctx;
struct sip_msg *msg;
if (_data.cs_route_number < 0)
return;
if (faked_msg_init_with_dlg_info(&data->callid, &data->from_uri, &data->from_tag,
&data->to_uri, &data->to_tag, &msg) != 0) {
LM_ERR("[%.*s]: error generating faked sip message\n", data->callid.len, data->callid.s);
return;
}
init_run_actions_ctx(&ra_ctx);
//run_top_route(event_rt.rlist[_data.cs_route_number], msg, &ra_ctx);
@ -958,6 +948,9 @@ static int __shm_str_hash_alloc(struct str_hash_table *ht, int size) {
}
int terminate_call(call_t *call) {
sip_msg_t *dmsg = NULL;
sip_data_t *data = NULL;
LM_DBG("Got kill signal for call [%.*s] client [%.*s] h_id [%u] h_entry [%u]. Dropping it now\n",
call->sip_data.callid.len,
call->sip_data.callid.s,
@ -970,6 +963,14 @@ int terminate_call(call_t *call) {
struct mi_node *node, *node1 = NULL;
struct mi_cmd *end_dlg_cmd = NULL;
if (_data.cs_route_number >= 0) {
data = &call->sip_data;
if (faked_msg_init_with_dlg_info(&data->callid, &data->from_uri, &data->from_tag,
&data->to_uri, &data->to_tag, &dmsg) != 0) {
LM_ERR("[%.*s]: error generating faked sip message\n", data->callid.len, data->callid.s);
dmsg = NULL;
}
}
root = init_mi_tree(0, 0, 0);
if (root == NULL) {
LM_ERR("Error initializing tree to terminate call\n");
@ -1006,7 +1007,7 @@ int terminate_call(call_t *call) {
free_mi_tree(root);
free_mi_tree(result);
__notify_call_termination(&call->sip_data);
if(dmsg) __notify_call_termination(dmsg);
return 0;
}

@ -22,7 +22,7 @@
*
*/
#ifndef CNXCC_STORAGE_H_
#ifndef CNXCC_REDIS_H_
#define CNXCC_REDIS_H_
#include <hiredis/hiredis.h>

@ -156,6 +156,7 @@ static const char* corex_rpc_shm_status_doc[2] = {
*/
static void corex_rpc_shm_status(rpc_t* rpc, void* ctx)
{
LM_DBG("printing shared memory status report\n");
shm_status();
}
@ -169,6 +170,7 @@ static const char* corex_rpc_shm_summary_doc[2] = {
*/
static void corex_rpc_shm_summary(rpc_t* rpc, void* ctx)
{
LM_DBG("printing shared memory summary report\n");
shm_sums();
}

@ -614,12 +614,15 @@ inline static int binrpc_bytes_needed(struct binrpc_parse_ctx *ctx)
/* prefill v with the requested type, if type==BINRPC_T_ALL it
* will be replaced by the actual record type
* known problems: no support for arrays inside STRUCT
* param smode: allow simple vals inside struct (needed for
* not-strict-formatted rpc responses)
* returns position after the record and *err==0 if succesfull
* original position and *err<0 if not */
inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
unsigned char* buf,
unsigned char* end,
struct binrpc_val* v,
int smode,
int* err
)
{
@ -664,18 +667,30 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
goto error_type;
}
v->type=type;
if (ctx->in_struct){
switch(type){
case BINRPC_T_STRUCT:
switch(type){
case BINRPC_T_STRUCT:
if (ctx->in_struct){
if (end_tag){
ctx->in_struct--;
v->u.end=1;
}else{
goto error_record;
if(smode==0) {
goto error_record;
} else {
v->u.end=0;
ctx->in_struct++;
}
}
break;
case BINRPC_T_AVP:
/* name | value */
} else {
if (end_tag)
goto error_record;
v->u.end=0;
ctx->in_struct++;
}
break;
case BINRPC_T_AVP:
/* name | value */
if (ctx->in_struct){
v->name.s=(char*)p;
v->name.len=(len-1); /* don't include 0 term */
p+=len;
@ -689,7 +704,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
tmp=ctx->in_struct;
ctx->in_struct=0; /* hack to parse a normal record */
v->type=type; /* hack */
p=binrpc_read_record(ctx, p, end, v, err);
p=binrpc_read_record(ctx, p, end, v, smode, err);
if (err<0){
ctx->in_struct=tmp;
goto error;
@ -701,50 +716,51 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
}else{
goto error_record;
}
break;
default:
goto error_record;
}
}else{
switch(type){
case BINRPC_T_INT:
p=binrpc_read_int(&v->u.intval, len, p, end, err);
break;
case BINRPC_T_STR:
v->u.strval.s=(char*)p;
v->u.strval.len=(len-1); /* don't include terminating 0 */
p+=len;
break;
case BINRPC_T_BYTES:
v->u.strval.s=(char*)p;
v->u.strval.len=len;
p+=len;
case BINRPC_T_STRUCT:
if (end_tag)
goto error_record;
v->u.end=0;
ctx->in_struct++;
break;
case BINRPC_T_ARRAY:
if (end_tag){
if (ctx->in_array>0){
ctx->in_array--;
v->u.end=1;
}else
goto error_record;
} else {
goto error_type;
}
break;
case BINRPC_T_INT:
if (ctx->in_struct && smode==0) goto error_record;
p=binrpc_read_int(&v->u.intval, len, p, end, err);
break;
case BINRPC_T_STR:
if (ctx->in_struct && smode==0) goto error_record;
v->u.strval.s=(char*)p;
v->u.strval.len=(len-1); /* don't include terminating 0 */
p+=len;
break;
case BINRPC_T_BYTES:
if (ctx->in_struct && smode==0) goto error_record;
v->u.strval.s=(char*)p;
v->u.strval.len=len;
p+=len;
case BINRPC_T_ARRAY:
if (ctx->in_struct && smode==0) goto error_record;
if (end_tag){
if (ctx->in_array>0){
ctx->in_array--;
v->u.end=1;
}else{
ctx->in_array++;
v->u.end=0;
goto error_record;
}
break;
case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
inside an int */
p=binrpc_read_int(&i, len, p, end, err);
v->u.fval=((double)i)/1000;
break;
default:
}else{
ctx->in_array++;
v->u.end=0;
}
break;
case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
inside an int */
if (ctx->in_struct && smode==0) goto error_record;
p=binrpc_read_int(&i, len, p, end, err);
v->u.fval=((double)i)/1000;
break;
default:
if (ctx->in_struct){
goto error_record;
} else {
goto error_type;
}
}
}
ctx->offset+=(int)(p-buf);
no_offs_update:

@ -655,7 +655,7 @@ int process_rpc_req(unsigned char* buf, int size, int* bytes_needed,
/* get rpc method */
val.type=BINRPC_T_STR;
f_ctx.in.s=binrpc_read_record(ctx, f_ctx.in.s, f_ctx.in.end, &val, &err);
f_ctx.in.s=binrpc_read_record(ctx, f_ctx.in.s, f_ctx.in.end, &val, 0, &err);
if (err<0){
LOG(L_CRIT, "ERROR: bad rpc request method, binrpc error: %s (%d)\n",
binrpc_error(err), err);
@ -857,7 +857,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
case 'd': /* int */
v.type=autoconv?BINRPC_T_ALL:BINRPC_T_INT;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v, &err);
ctx->in.end, &v, 0, &err);
if (err<0 || ((i=binrpc_val_conv_int(&v, &err))==0 && err<0))
goto error_read;
*(va_arg(ap, int*))=i;
@ -865,7 +865,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
case 'f':
v.type=autoconv?BINRPC_T_ALL:BINRPC_T_DOUBLE;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v, &err);
ctx->in.end, &v, 0, &err);
if (err<0 || ((d=binrpc_val_conv_double(&v, &err))==0 &&
err<0))
goto error_read;
@ -875,7 +875,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
case 'S': /* str */
v.type=autoconv?BINRPC_T_ALL:BINRPC_T_STR;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v,&err);
ctx->in.end, &v, 0, &err);
if (err<0 || ((s=binrpc_val_conv_str(ctx, &v, &err))==0 &&
err<0)){
v.u.strval.s="if you get this string, you don't"
@ -895,7 +895,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
/* FIXME: structure reading doesn't work for now */
#if 0
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v, &err);
ctx->in.end, &v, 0, &err);
if (err<0) goto error_read;
ctx->in.in_struct++;
*(va_arg(ap, void**))=ctx; /* use the same context */

@ -71,6 +71,10 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
memset(ptr, 0, sizeof(struct pg_con));
ptr->ref = 1;
memset(keywords, 0, (sizeof(char*) * 10));
memset(values, 0, (sizeof(char*) * 10));
memset(to, 0, (sizeof(char) * 16));
if (id->port) {
ports = int2str(id->port, 0);
keywords[i] = "port";

@ -711,15 +711,23 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
&sflags_column, &toroute_name_column, &req_uri_column,
&xdata_column, &iflags_column };
if(cell->state<DLG_STATE_EARLY || cell->state==DLG_STATE_DELETED) {
LM_DBG("not storing dlg in db during initial or deleted states\n");
return 0;
}
i = 0;
if( (cell->dflags & DLG_FLAG_NEW) != 0
|| (cell->dflags & DLG_FLAG_CHANGED_VARS) != 0) {
/* iterate the list */
for(var=cell->vars ; var ; var=var->next) {
if (update_dialog_vars_dbinfo(cell, var) != 0)
return -1;
i++;
}
/* Remove the flag */
cell->dflags &= ~DLG_FLAG_CHANGED_VARS;
LM_DBG("updated %d vars for dlg [%d:%d]\n", i, cell->h_entry, cell->h_id);
}
if(use_dialog_table()!=0)
@ -854,43 +862,31 @@ error:
int update_dialog_dbinfo(struct dlg_cell * cell)
{
struct dlg_entry entry;
/* lock the entry */
entry = (d_table->entries)[cell->h_entry];
dlg_lock( d_table, &entry);
dlg_lock(d_table, &d_table->entries[cell->h_entry]);
if (update_dialog_dbinfo_unsafe(cell) != 0) {
dlg_unlock( d_table, &entry);
dlg_unlock(d_table, &d_table->entries[cell->h_entry]);
return -1;
}
dlg_unlock( d_table, &entry);
dlg_unlock(d_table, &d_table->entries[cell->h_entry]);
return 0;
}
void dialog_update_db(unsigned int ticks, void * param)
{
int index;
struct dlg_entry entry;
struct dlg_cell * cell;
int i;
struct dlg_cell *cell;
LM_DBG("saving current_info \n");
for(index = 0; index< d_table->size; index++){
/* lock the whole entry */
entry = (d_table->entries)[index];
dlg_lock( d_table, &entry);
for(cell = entry.first; cell != NULL; cell = cell->next){
if (update_dialog_dbinfo_unsafe(cell) != 0) {
dlg_unlock( d_table, &entry);
goto error;
}
}
dlg_unlock( d_table, &entry);
for(i = 0; i < d_table->size; i++){
/* lock the slot */
dlg_lock(d_table, &d_table->entries[i]);
for(cell = d_table->entries[i].first; cell != NULL; cell = cell->next){
/* if update fails for one dlg, still do it for the next ones */
update_dialog_dbinfo_unsafe(cell);
}
dlg_unlock(d_table, &d_table->entries[i]);
}
return;
error:
dlg_unlock( d_table, &entry);
}

@ -766,7 +766,6 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
str ttag;
str req_uri;
unsigned int dir;
int mlock;
dlg = dlg_get_ctx_dialog();
if(dlg != NULL) {
@ -792,17 +791,15 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
trim(&req_uri);
dir = DLG_DIR_NONE;
mlock = 1;
/* search dialog by SIP attributes
* - if not found, hash table slot is left locked, to avoid races
* to add 'same' dialog on parallel forking or not-handled-yet
* retransmissions. Release slot after linking new dialog */
dlg = search_dlg(&callid, &ftag, &ttag, &dir);
* - hash table slot is left locked */
dlg = dlg_search(&callid, &ftag, &ttag, &dir);
if(dlg) {
mlock = 0;
if (detect_spirals) {
if (spiral_detected == 1)
if (spiral_detected == 1) {
dlg_hash_release(&callid);
return 0;
}
if ( dlg->state != DLG_STATE_DELETED ) {
LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
@ -817,10 +814,11 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
_dlg_ctx.iuid.h_id = dlg->h_id;
/* search_dlg() has incremented the ref count by 1 */
dlg_release(dlg);
dlg_hash_release(&callid);
return 0;
}
dlg_release(dlg);
}
}
}
spiral_detected = 0;
@ -831,7 +829,7 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
&req_uri /*r-uri*/ );
if (dlg==0) {
if(likely(mlock==1)) dlg_hash_release(&callid);
dlg_hash_release(&callid);
LM_ERR("failed to create new dialog\n");
return -1;
}
@ -839,7 +837,7 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
/* save caller's tag, cseq, contact and record route*/
if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
&(get_from(req)->tag_value)) !=0) {
if(likely(mlock==1)) dlg_hash_release(&callid);
dlg_hash_release(&callid);
LM_ERR("could not add further info to the dialog\n");
shm_free(dlg);
return -1;
@ -848,9 +846,10 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
/* Populate initial varlist: */
dlg->vars = get_local_varlist_pointer(req, 1);
/* if search_dlg() returned NULL, slot was kept locked */
link_dlg(dlg, 0, mlock);
if(likely(mlock==1)) dlg_hash_release(&callid);
/* after dlg_search() slot was kept locked */
link_dlg(dlg, 0, 1);
/* unlock after dlg_search() */
dlg_hash_release(&callid);
dlg->lifetime = get_dlg_timeout(req);
s.s = _dlg_ctx.to_route_name;
@ -1402,8 +1401,13 @@ void dlg_ontimeout(struct dlg_tl *tl)
if(dlg->iflags&DLG_IFLAG_TIMEOUTBYE)
{
/* set the dialog context so that it's available in
* tm:local-request event route */
dlg_set_ctx_iuid(dlg);
if(dlg_bye_all(dlg, NULL)<0)
dlg_unref(dlg, 1);
dlg_reset_ctx_iuid();
/* run event route for end of dlg */
dlg_run_event_route(dlg, NULL, dlg->state, DLG_STATE_DELETED);

@ -651,7 +651,7 @@ dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid)
* \param ftag from tag
* \param ttag to tag
* \param dir direction
* \param mode let hash table slot locked if dialog is not found
* \param mode let hash table slot locked or not
* \return dialog structure on success, NULL on failure
*/
static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
@ -669,7 +669,7 @@ static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
/* Check callid / fromtag / totag */
if (match_dialog( dlg, callid, ftag, ttag, dir)==1) {
ref_dlg_unsafe(dlg, 1);
dlg_unlock( d_table, d_entry);
if(likely(mode==0)) dlg_unlock( d_table, d_entry);
LM_DBG("dialog callid='%.*s' found on entry %u, dir=%d\n",
callid->len, callid->s,h_entry,*dir);
return dlg;
@ -725,15 +725,15 @@ struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
* referred to as a dialog."
* Note that the caller is responsible for decrementing (or reusing)
* the reference counter by one again if a dialog has been found.
* If the dialog is not found, the hash slot is left locked, to allow
* linking the structure of a new dialog.
* Important: the hash slot is left locked (e.g., needed to allow
* linking the structure of a new dialog).
* \param callid callid
* \param ftag from tag
* \param ttag to tag
* \param dir direction
* \return dialog structure on success, NULL on failure (and slot locked)
*/
dlg_cell_t* search_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
dlg_cell_t* dlg_search( str *callid, str *ftag, str *ttag, unsigned int *dir)
{
struct dlg_cell *dlg;
unsigned int he;
@ -749,6 +749,21 @@ dlg_cell_t* search_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
}
/*!
* \brief Lock hash table slot by call-id
* \param callid call-id value
*/
void dlg_hash_lock(str *callid)
{
unsigned int he;
struct dlg_entry *d_entry;
he = core_hash(callid, 0, d_table->size);
d_entry = &(d_table->entries[he]);
dlg_lock(d_table, d_entry);
}
/*!
* \brief Release hash table slot by call-id
* \param callid call-id value
@ -764,7 +779,6 @@ void dlg_hash_release(str *callid)
}
/*!
* \brief Link a dialog structure
* \param dlg dialog

@ -335,15 +335,22 @@ dlg_cell_t* get_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
* referred to as a dialog."
* Note that the caller is responsible for decrementing (or reusing)
* the reference counter by one again if a dialog has been found.
* If the dialog is not found, the hash slot is left locked, to allow
* linking the structure of a new dialog.
* Important: the hash slot is left locked (e.g., needed to allow
* linking the structure of a new dialog).
* \param callid callid
* \param ftag from tag
* \param ttag to tag
* \param dir direction
* \return dialog structure on success, NULL on failure (and slot locked)
*/
dlg_cell_t* search_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
dlg_cell_t* dlg_search(str *callid, str *ftag, str *ttag, unsigned int *dir);
/*!
* \brief Lock hash table slot by call-id
* \param callid call-id value
*/
void dlg_hash_lock(str *callid);
/*!

@ -394,6 +394,7 @@ int remove_profile(dlg_profile_table_t *profile, str *value, str *puid)
lh->next = lh->prev = NULL;
if(lh->linker) shm_free(lh->linker);
p_entry->content--;
lock_release(&profile->lock );
return 1;
}
lh = lh->next;

@ -40,7 +40,7 @@ dlg_ctx_t _dlg_ctx;
extern int spiral_detected;
/*! global variable table, in case the dialog does not exist yet */
struct dlg_var * var_table = 0;
static struct dlg_var *_dlg_var_table = 0;
/*! ID of the current message */
int msg_id;
@ -99,7 +99,7 @@ static inline struct dlg_var *new_dlg_var(str *key, str *val)
LM_ERR("no more shm mem\n");
return NULL;
}
var->next = NULL;
memset(var, 0, sizeof(struct dlg_var));
var->vflags = DLG_FLAG_NEW;
/* set key */
var->key.len = key->len;
@ -113,7 +113,7 @@ static inline struct dlg_var *new_dlg_var(str *key, str *val)
var->key.s[var->key.len] = '\0';
/* set value */
var->value.len = val->len;
var->value.s = (char*)shm_malloc(var->value.len);
var->value.s = (char*)shm_malloc(var->value.len+1);
if (var->value.s==NULL) {
shm_free(var->key.s);
shm_free(var);
@ -121,19 +121,21 @@ static inline struct dlg_var *new_dlg_var(str *key, str *val)
return NULL;
}
memcpy(var->value.s, val->s, val->len);
var->value.s[var->value.len] = '\0';
return var;
}
/*! Delete the current var-list */
void free_local_varlist() {
struct dlg_var *var;
while (var_table) {
var = var_table;
var_table = var_table->next;
while (_dlg_var_table) {
var = _dlg_var_table;
_dlg_var_table = _dlg_var_table->next;
shm_free(var->key.s);
shm_free(var->value.s);
shm_free(var);
}
_dlg_var_table = NULL;
}
/*! Retrieve the local var-list pointer */
@ -144,9 +146,9 @@ struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointe
free_local_varlist();
msg_id = msg->id;
}
var = var_table;
var = _dlg_var_table;
if (clear_pointer)
var_table = NULL;
_dlg_var_table = NULL;
return var;
}
@ -161,7 +163,7 @@ int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val)
if (dlg)
var_list = &dlg->vars;
else
var_list = &var_table;
var_list = &_dlg_var_table;
if ( val && (var=new_dlg_var(key, val))==NULL) {
LM_ERR("failed to create new dialog variable\n");
@ -216,7 +218,7 @@ str * get_dlg_variable_unsafe(struct dlg_cell *dlg, str *key)
if (dlg)
var_list = dlg->vars;
else
var_list = var_table;
var_list = _dlg_var_table;
/* iterate the list */
for(var=var_list ; var ; var=var->next) {
@ -244,7 +246,7 @@ int pv_parse_dialog_var_name(pv_spec_p sp, str *in)
/*! Internal debugging function: Prints the list of dialogs */
void print_lists(struct dlg_cell *dlg) {
struct dlg_var *varlist;
varlist = var_table;
varlist = _dlg_var_table;
LM_DBG("Internal var-list (%p):\n", varlist);
while (varlist) {
LM_DBG("%.*s=%.*s (flags %i)\n",

@ -219,6 +219,7 @@ int ds_set_attrs(ds_dest_t *dest, str *attrs)
dest->attrs.socket = pit->body;
}
}
if(params_list) free_params(params_list);
return 0;
}

@ -51,7 +51,10 @@ static int add_contact(str aor, ucontact_info_t* ci)
str contact;
int res;
dmq_ul.get_udomain("location", &_d);
if (dmq_ul.get_udomain("location", &_d) < 0) {
LM_ERR("Failed to get domain\n");
return -1;
}
res = dmq_ul.get_urecord(_d, &aor, &r);
if (res < 0) {
LM_ERR("failed to retrieve record from usrloc\n");
@ -92,6 +95,33 @@ static int add_contact(str aor, ucontact_info_t* ci)
return -1;
}
static int delete_contact(str aor, ucontact_info_t* ci)
{
udomain_t* _d;
urecord_t* r;
ucontact_t* c;
if (dmq_ul.get_udomain("location", &_d) < 0) {
LM_ERR("Failed to get domain\n");
return -1;
}
if (dmq_ul.get_urecord_by_ruid(_d, dmq_ul.get_aorhash(&aor),
&ci->ruid, &r, &c) != 0) {
LM_WARN("AOR/Contact not found\n");
return -1;
}
if (dmq_ul.delete_ucontact(r, c) != 0) {
dmq_ul.unlock_udomain(_d, &aor);
LM_WARN("could not delete contact\n");
return -1;
}
dmq_ul.release_urecord(r);
dmq_ul.unlock_udomain(_d, &aor);
return 0;
}
void usrloc_get_all_ucontact(dmq_node_t* node)
{
int rval, len=0;
@ -116,6 +146,12 @@ void usrloc_get_all_ucontact(dmq_node_t* node)
LM_ERR("dmq_ul.get_all_ucontacts is NULL\n");
goto done;
}
if (dmq_ul.get_udomain("location", &_d) < 0) {
LM_ERR("Failed to get domain\n");
goto done;
}
rval = dmq_ul.get_all_ucontacts(buf, len, 0, 0, 1);
if (rval<0) {
LM_ERR("failed to fetch contacts\n");
@ -161,8 +197,6 @@ void usrloc_get_all_ucontact(dmq_node_t* node)
memcpy( &aorhash, cp, sizeof(aorhash));
cp = (char*)cp + sizeof(aorhash);
dmq_ul.get_udomain("location", &_d);
res = dmq_ul.get_urecord_by_ruid(_d, aorhash, &ruid, &r, &ptr);
aor = r->aor;
if (res > 0) {
@ -357,6 +391,7 @@ int usrloc_dmq_handle_msg(struct sip_msg* msg, peer_reponse_t* resp, dmq_node_t*
break;
case DMQ_RM:
LM_DBG("Received DMQ_RM. Delete contact info...\n");
delete_contact(aor, &ci);
break;
case DMQ_SYNC:
LM_DBG("Received DMQ_SYNC. Sending all contacts...\n");
@ -510,8 +545,7 @@ void dmq_ul_cb_contact(ucontact_t* ptr, int type, void* param)
usrloc_dmq_send_contact(ptr, aor, DMQ_UPDATE, 0);
break;
case UL_CONTACT_DELETE:
//usrloc_dmq_send_contact(ptr, aor, DMQ_RM);
LM_DBG("Contact <%.*s> deleted\n", aor.len, aor.s);
usrloc_dmq_send_contact(ptr, aor, DMQ_RM, 0);
break;
case UL_CONTACT_EXPIRE:
//usrloc_dmq_send_contact(ptr, aor, DMQ_UPDATE);

@ -210,9 +210,9 @@ static int mod_init(void)
goto error;
}
memset(hash_table_1, 0, sizeof(struct domain_list *) *
DOM_HASH_SIZE + 1);
(DOM_HASH_SIZE + 1));
memset(hash_table_2, 0, sizeof(struct domain_list *) *
DOM_HASH_SIZE + 1);
(DOM_HASH_SIZE + 1));
*hash_table = hash_table_1;
/* Allocate and initialize locks */

@ -10,7 +10,7 @@ Edited by
Anca-Maria Vamanu
Copyright © 2005-2008 Voice Sistem SRL
Copyright © 2005-2008 Voice Sistem SRL
__________________________________________________________________
Table of Contents
@ -234,7 +234,7 @@ Chapter 1. Admin Guide
1.4.1. Gateway Addresses
Default name for the table storing gateway addresses is “dr_gateways”.
Default name for the table storing gateway addresses is "dr_gateways".
Gateway addresses are stored in a separate table because of need to
access them independent of Dynamic Routing processing (e.g., adding/
removing gateway PRI prefix before/after performing other operation --
@ -270,12 +270,12 @@ Chapter 1. Admin Guide
group of destinations is delimited by semi-colon char. inside the whole
destination list ( like: 2,4;5,78,23;4;7;2 ). The destinations from
within a group may be act differently (like load-balancing, random
selection, etc), depending of the “sort_order” module parameter - more
selection, etc), depending of the "sort_order" module parameter - more
about this is available under the module paramters section.
1.4.3. Routing Rules
Default name for the table storing rule definitions is “dr_rules”.
Default name for the table storing rule definitions is "dr_rules".
Table 1.3. Definition of dr_rules table
Column name Type Default Description
@ -304,18 +304,18 @@ Chapter 1. Admin Guide
draft 09):
Table 1.4. Time recurrence attributes
Attribute Description
dastard Start of interval (RFC 2445 DATE-TIME)
duration Length of interval (RFC 2445 DURATION)
freq Frequency of recurrence (secondly,minutely,hourly, daily,weekly,
monthly, or yearly).
until bound of recurrence (RFC 2445 DATE-TIME)
interval How often the recurrence repeats
byday List of days of the week
bymonthday List of days of the month
byyearday List of days of the year
byweekno List of weeks of the year
bymonth List of months of the year
Attribute Description
dastard Start of interval (RFC 2445 DATE-TIME)
duration Length of interval (RFC 2445 DURATION)
freq Frequency of recurrence (secondly,minutely,hourly, daily,weekly,
monthly, or yearly).
until bound of recurrence (RFC 2445 DATE-TIME)
interval How often the recurrence repeats
byday List of days of the week
bymonthday List of days of the month
byyearday List of days of the year
byweekno List of weeks of the year
bymonth List of months of the year
The value stored in database has the format of:
<dtstart>|<duration>|<freq>|<until>|<interval>|<byday>|<bymonthday>
|<byyearday>|<byweekno>|<bymonth>
@ -325,48 +325,52 @@ Chapter 1. Admin Guide
Detailed description of time recurrence attributes:
+ dtstart - specifies the beginning of the first period.
+ duration - specifies the duration of the period. For a
recurring interval, the “duration” parameter MUST be small
recurring interval, the "duration" parameter MUST be small
enough such that subsequent intervals do not overlap. For
non-recurring intervals, durations of any positive length are
permitted, zero-length duration means “forever”.
Negative-length durations are not allowed.
+ freq - takes one of the following values: “daily”, to specify
permitted, zero-length duration means "forever".
Negative-length durations are not allowed. In the common case
of a duration less than one day, the value starts with 'PT'
followed by number of hours, minutes and seconds, e.g., a
duration of 8 hours and 30 minutes is written 'PT8H30M'. See
RFC 2445 DURATION specifications for full format.
+ freq - takes one of the following values: "daily", to specify
repeating periods based on an interval of a day or more;
“weekly”, to specify repeating periods based on an interval of
a week or more; “monthly”, to specify repeating periods based
on an interval of a month or more; and “yearly”, to specify
"weekly", to specify repeating periods based on an interval of
a week or more; "monthly", to specify repeating periods based
on an interval of a month or more; and "yearly", to specify
repeating periods based on an interval of a year or more.
These values are not case-sensitive.
+ until - defines an iCalendar COS DATE or DATE-TIME value which
bounds the recurrence rule in an inclusive manner. If the
value specified by “until” is synchronized with the specified
value specified by "until" is synchronized with the specified
recurrence, this date or date-time becomes the last instance
of the recurrence. If not present, the recurrence is
considered to repeat forever.
+ interval - contains a positive integer representing how often
the recurrence rule repeats. The default value is “1”, meaning
every day for a “daily” rule, every week for a “weekly” rule,
every month for a “monthly” rule and every year for a “yearly”
the recurrence rule repeats. The default value is "1", meaning
every day for a "daily" rule, every week for a "weekly" rule,
every month for a "monthly" rule and every year for a "yearly"
rule.
+ interval - contains a positive integer representing how often
the recurrence rule repeats. The default value is “1”, meaning
every day for a “daily” rule, every week for a “weekly” rule,
every month for a “monthly” rule and every year for a “yearly”
the recurrence rule repeats. The default value is "1", meaning
every day for a "daily" rule, every week for a "weekly" rule,
every month for a "monthly" rule and every year for a "yearly"
rule.
+ byday - specifies a comma-separated list of days of the week.
“MO” indicates Monday; “TU” indicates Tuesday; “WE” indicates
Wednesday; “TH” indicates Thursday; “FR” indicates Friday;
“SA” indicates Saturday; “SU” indicates Sunday. These values
"MO" indicates Monday; "TU" indicates Tuesday; "WE" indicates
Wednesday; "TH" indicates Thursday; "FR" indicates Friday;
"SA" indicates Saturday; "SU" indicates Sunday. These values
are not case-sensitive.
Each “byday” value can also be preceded by a positive (+n) or
Each "byday" value can also be preceded by a positive (+n) or
negative (-n) integer. If present, this indicates the nth
occurrence of the specific day within the “monthly” or
“yearly” recurrence. For example, within a “monthly” rule,
occurrence of the specific day within the "monthly" or
"yearly" recurrence. For example, within a "monthly" rule,
+1MO (or simply 1MO) represents the first Monday within the
month, whereas -1MO represents the last Monday of the month.
If an integer modifier is not present, it means all days of
this type within the specified frequency. For example, within
a “monthly” rule, MO represents all Mondays within the month.
a "monthly" rule, MO represents all Mondays within the month.
+ bymonthday - parameter specifies a comma-separated list of
days of the month. Valid values are 1 to 31 or -31 to -1. For
example, -10 represents the tenth to the last day of the
@ -380,37 +384,37 @@ Chapter 1. Admin Guide
to -1.
+ bymonth - parameter specifies a comma-separated list of months
of the year. Valid values are 1 to 12.
A recurrence is specified by including the “freq” parameter, which
A recurrence is specified by including the "freq" parameter, which
indicates the type of recurrence rule. Parameters other than
“dtstart” and “duration” SHOULD NOT be specified unless “freq” is
"dtstart" and "duration" SHOULD NOT be specified unless "freq" is
present.
If byxxx parameter values are found which are beyond the available
scope (ie, bymonthday=“30” in February), they are simply ignored.
scope (ie, bymonthday="30" in February), they are simply ignored.
Byxxx parameters modify the recurrence in some manner. Byxxx rule
parts for a period of time which is the same or greater than the
frequency generally reduce or limit the number of occurrences of
the recurrence generated. For example, freq=“daily” bymonth=“1”
the recurrence generated. For example, freq="daily" bymonth="1"
reduces the number of recurrence instances from all days (if the
“bymonth” parameter is not present) to all days in January. Byxxx
"bymonth" parameter is not present) to all days in January. Byxxx
parameters for a period of time less than the frequency generally
increase or expand the number of occurrences of the recurrence. For
example, freq=“yearly” bymonth=“1,2” increases the number of days
within the yearly recurrence set from 1 (if “bymonth” parameter is
example, freq="yearly" bymonth="1,2" increases the number of days
within the yearly recurrence set from 1 (if "bymonth" parameter is
not present) to 2.
If multiple Byxxx parameters are specified, then after evaluating
the specified “freq” and “interval” parameters, the Byxxx
the specified "freq" and "interval" parameters, the Byxxx
parameters are applied to the current set of evaluated occurrences
in the following order: “bymonth”, “byweekno”, “byyearday”,
“bymonthday”, “byday”; then “until” is evaluated.
in the following order: "bymonth", "byweekno", "byyearday",
"bymonthday", "byday"; then "until" is evaluated.
Here is an example of evaluating multiple Byxxx parameters.
dtstart=“19970105T083000” duration=“10M” freq=“yearly” interval=“2”
bymonth=“1” byday=“SU”
First, the interval=“2” would be applied to freq=“yearly” to arrive
at “every other year” . Then, bymonth=“1” would be applied to
arrive at “every January, every other year”. Then, byday=“SU” would
be applied to arrive at every Sunday in January, every other year,
from 8:30 to 8:40 . The appropriate minutes and hours have been
retrieved from the “dtstart” and “duration” parameters.
dtstart="19970105T083000" duration="PT10M" freq="yearly"
interval="2" bymonth="1" byday="SU"
First, the interval="2" would be applied to freq="yearly" to arrive
at "every other year" . Then, bymonth="1" would be applied to
arrive at "every January, every other year". Then, byday="SU" would
be applied to arrive at "every Sunday in January, every other year,
from 8:30 to 8:40 ". The appropriate minutes and hours have been
retrieved from the "dtstart" and "duration" parameters.
d. priority column
If many rules are eligible, choose the one with highest priority.
e. routeid column
@ -420,8 +424,8 @@ Chapter 1. Admin Guide
level.
f. gwlist column
A comma separated list of gateway identifiers corresponding to a
row in table “dr_gateways”. You can use a predefined list from the
table “dr_gw_lists” preceded by the character “#”. The first
row in table "dr_gateways". You can use a predefined list from the
table "dr_gw_lists" preceded by the character "#". The first
gateway is tried first and if routing to it fails, then the second
one, and so one. If no gateway is left a negative response is sent
back to caller.
@ -433,7 +437,7 @@ Chapter 1. Admin Guide
2 8 0049 20040101T083000 0 0 1,2 Rule 2
3 7,8,9 0049 20040101T083000 0 0 3 Rule 3
(The time recurrence for first rule is:
“20040101T083000|10H|weekly|||MO,TU,WE,TH,FR”)
"20040101T083000|10H|weekly|||MO,TU,WE,TH,FR")
1.5. Routing Rule Processing
@ -501,7 +505,7 @@ Chapter 1. Admin Guide
The database url.
Default value is “NULL”.
Default value is "NULL".
Example 1.1. Set db_url parameter
...
@ -513,7 +517,7 @@ modparam("drouting", "db_url",
The name of the db table storing gateway addresses.
Default value is “dr_gateways”.
Default value is "dr_gateways".
Example 1.2. Set drd_table parameter
...
@ -524,7 +528,7 @@ modparam("drouting", "drd_table", "dr_gateways")
The name of the db table storing routing rules.
Default value is “dr_rules”.
Default value is "dr_rules".
Example 1.3. Set drr_table parameter
...
@ -535,7 +539,7 @@ modparam("drouting", "drr_table", "rules")
The name of the db table storing groups.
Default value is “dr_groups”.
Default value is "dr_groups".
Example 1.4. Set drg_table parameter
...
@ -550,7 +554,7 @@ modparam("drouting", "drg_table", "groups")
individual elements. Very useful to reuse a list of gateways in
different places.
Default value is “dr_gw_lists”.
Default value is "dr_gw_lists".
Example 1.5. Set drl_table parameter
...
@ -581,7 +585,7 @@ modparam("drouting", "drl_table", "my_gw_lists")
case there are 2 failures, all the three gateways (1,2,3) will be
tried in a random order.
Default value is “0”.
Default value is "0".
Example 1.6. Set sort_order parameter
...
@ -593,7 +597,7 @@ modparam("drouting", "sort_order", 2)
The name of the avp for storing Request URIs to be later used
(alternative destiantions for the current one).
Default value is “NULL”.
Default value is "NULL".
Example 1.7. Set ruri_avp parameter
...
@ -608,7 +612,7 @@ modparam("drouting", "ruri_avp", '$avp(i:33)')
function), the AVP will be updated with the attrs of the new used
destination.
Default value is “NULL”.
Default value is "NULL".
Example 1.8. Set attrs_avp parameter
...
@ -621,7 +625,7 @@ modparam("drouting", "atrrs_avp", '$avp(i:67)')
Flag to configure whether to use domain match when querying database
for user's routing group.
Default value is “1”.
Default value is "1".
Example 1.9. Set use_domain parameter
...
@ -632,7 +636,7 @@ modparam("drouting", "use_domain", 0)
The name of the column in group db table where the username is stored.
Default value is “username”.
Default value is "username".
Example 1.10. Set drg_user_col parameter
...
@ -643,7 +647,7 @@ modparam("drouting", "drg_user_col", "user")
The name of the column in group db table where the domain is stored.
Default value is “domain”.
Default value is "domain".
Example 1.11. Set drg_domain_col parameter
...
@ -654,7 +658,7 @@ modparam("drouting", "drg_domain_col", "host")
The name of the column in group db table where the group id is stored.
Default value is “groupid”.
Default value is "groupid".
Example 1.12. Set drg_grpid_col parameter
...
@ -666,7 +670,7 @@ modparam("drouting", "drg_grpid_col", "grpid")
The number of rows that should be fetched from the result of a query in
rules db table.
Default value is “2000”.
Default value is "2000".
Example 1.13. Set fetch_rows parameter
...
@ -679,7 +683,7 @@ modparam("drouting", "fetch_rows", 1500)
startup. If not enabled, the GW name will be blindly used during
routing.
Default value is “1 (enabled)”.
Default value is "1 (enabled)".
Example 1.14. Set force_dns parameter
...
@ -694,7 +698,7 @@ modparam("drouting", "force_dns", 0)
4.4. is_from_gw([type])
4.5. is_from_gw( type, [flag])
4.1. do_routing("[groupID]")
4.1. do_routing("[groupID]")
Function to trigger routing of the message according to the rules in
the database table and the configured parameters.
@ -714,7 +718,7 @@ do_routing("0");
...
do_routing("$avp(i:10)");
4.2. use_next_gw()/next_routing()
4.2. use_next_gw()/next_routing()
The function takes the next available destination (set by do_routing,
as alternative destinations) and push it into RURI. Note that the
@ -737,7 +741,7 @@ if (use_next_gw()) {
}
...
4.3. goes_to_gw([type])
4.3. goes_to_gw([type])
Function returns true if the destination of the current request
(destination URI or Request URI) points (as IP) to one of the gateways.
@ -758,7 +762,7 @@ if (goes_to_gw("1")) {
}
...
4.4. is_from_gw([type])
4.4. is_from_gw([type])
The function checks if the sender of the message is a gateway from a
certain group.
@ -777,7 +781,7 @@ if (is_from_gw("1") {
}
...
4.5. is_from_gw( type, [flag])
4.5. is_from_gw( type, [flag])
The function checks if the sender of the message is a gateway from a
certain group.
@ -799,7 +803,7 @@ if (is_from_gw("3","1") {
5.1. drouting.reload
5.1. drouting.reload
5.1. drouting.reload
Command to reload routing rules from database.

@ -469,7 +469,11 @@
be small enough such that subsequent intervals do not overlap.
For non-recurring intervals, durations of any positive length are
permitted, zero-length duration means <quote>forever</quote>.
Negative-length durations are not allowed.
Negative-length durations are not allowed. In the common case of
a duration less than one day, the value starts with 'PT' followed by
number of hours, minutes and seconds, e.g., a duration of 8 hours
and 30 minutes is written 'PT8H30M'. See RFC 2445 DURATION
specifications for full format.
</para>
</listitem>
<listitem>
@ -612,7 +616,7 @@
Here is an example of evaluating multiple Byxxx parameters.
</para>
<para>
dtstart=<quote>19970105T083000</quote> duration=<quote>10M</quote>
dtstart=<quote>19970105T083000</quote> duration=<quote>PT10M</quote>
freq=<quote>yearly</quote> interval=<quote>2</quote>
bymonth=<quote>1</quote> byday=<quote>SU</quote>
</para>

@ -466,7 +466,7 @@ static void rpc_reload(rpc_t *rpc, void *c)
return;
}
rpc->rpl_printf(c, "relaad OK");
rpc->rpl_printf(c, "reload ok");
return;
}

@ -160,8 +160,16 @@ modparam("evapi", "netstring_format", 0)
4.1. evapi_relay(evdata)
Relay the event data give as parameter to connected applications. The
format on the network is netstring with evdata payload.
Relay the event data given as parameter to connected applications.
The format on the network is netstring with evdata payload if
netstring_format parameter is set to 1 or bare evdata if
netstring_format parameter is set to 0.
The function is passing the task to evapi dispatcher process, therefore
the SIP worker process is not blocked. Also, it doesn't wait for any
response, therefore the processing of the configuration continues very
fast when executing evapi_relay().
This function can be used from ANY_ROUTE.
@ -182,10 +190,17 @@ evapi_relay("{ \"event\": \"test\",\n \"data\": { \"fU\": \"$fU\" }\n}");
4.2. evapi_async_relay(evdata)
Relay the event data give as parameter to connected applications. The
format on the network is netstring with evdata payload. Before
evaluating the parameter, the request processing is suspended using tm
module.
Relay the event data given as parameter to connected applications.
Before evaluating the parameter, the request processing is suspended
using tm module (using the t_suspend()/t_continue() framework). The
routing of the SIP request can be continued once
event_route[evapi:message-received] is triggered. After
evapi_async_relay() returns true, no relaying should happen in
request_route(), it should be followed by exit;.
The format on the network is netstring with evdata payload if
netstring_format parameter is set to 1 or bare evdata if
netstring_format parameter is set to 0.
This function can be used from REQUEST_ROUTE.

@ -36,6 +36,7 @@
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../ut.h"
#include "../../cfg/cfg_struct.h"
#include "../../lib/kcore/faked_msg.h"
#include "evapi_dispatch.h"
@ -44,12 +45,15 @@ static int _evapi_notify_sockets[2];
static int _evapi_netstring_format = 1;
#define EVAPI_IPADDR_SIZE 64
#define CLIENT_BUFFER_SIZE 32768
typedef struct _evapi_client {
int connected;
int sock;
unsigned short af;
unsigned short src_port;
char src_addr[EVAPI_IPADDR_SIZE];
char rbuffer[CLIENT_BUFFER_SIZE];
unsigned int rpos;
} evapi_client_t;
typedef struct _evapi_env {
@ -59,7 +63,8 @@ typedef struct _evapi_env {
} evapi_env_t;
#define EVAPI_MAX_CLIENTS 8
static evapi_client_t _evapi_clients[EVAPI_MAX_CLIENTS];
/* last one used for error handling, not a real connected client */
static evapi_client_t _evapi_clients[EVAPI_MAX_CLIENTS+1];
typedef struct _evapi_evroutes {
int con_new;
@ -224,26 +229,18 @@ int evapi_dispatch_notify(char *obuf, int olen)
*/
void evapi_recv_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
#define CLIENT_BUFFER_SIZE 4096
char rbuffer[CLIENT_BUFFER_SIZE];
ssize_t rlen;
int i, k;
evapi_env_t evenv;
str frame;
char *sfp;
char *efp;
if(EV_ERROR & revents) {
perror("received invalid event\n");
return;
}
/* read message from client */
rlen = recv(watcher->fd, rbuffer, CLIENT_BUFFER_SIZE-1, 0);
if(rlen < 0) {
LM_ERR("cannot read the client message\n");
return;
}
for(i=0; i<EVAPI_MAX_CLIENTS; i++) {
if(_evapi_clients[i].connected==1 && _evapi_clients[i].sock==watcher->fd) {
break;
@ -251,9 +248,24 @@ void evapi_recv_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
}
if(i==EVAPI_MAX_CLIENTS) {
LM_ERR("cannot lookup client socket %d\n", watcher->fd);
/* try to empty the socket anyhow */
rlen = recv(watcher->fd, _evapi_clients[i].rbuffer, CLIENT_BUFFER_SIZE-1, 0);
return;
}
/* read message from client */
rlen = recv(watcher->fd, _evapi_clients[i].rbuffer + _evapi_clients[i].rpos,
CLIENT_BUFFER_SIZE - 1 - _evapi_clients[i].rpos, 0);
if(rlen < 0) {
LM_ERR("cannot read the client message\n");
_evapi_clients[i].rpos = 0;
return;
}
cfg_update();
evapi_env_reset(&evenv);
if(rlen == 0) {
/* client is gone */
@ -262,6 +274,7 @@ void evapi_recv_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
evapi_run_cfg_route(&evenv, _evapi_rts.con_closed);
_evapi_clients[i].connected = 0;
_evapi_clients[i].sock = 0;
_evapi_clients[i].rpos = 0;
ev_io_stop(loop, watcher);
free(watcher);
LM_INFO("client closing connection - pos [%d] addr [%s:%d]\n",
@ -269,50 +282,97 @@ void evapi_recv_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
return;
}
rbuffer[rlen] = '\0';
_evapi_clients[i].rbuffer[_evapi_clients[i].rpos+rlen] = '\0';
LM_NOTICE("{%d} [%s:%d] - received [%.*s]\n",
LM_NOTICE("{%d} [%s:%d] - received [%.*s] (%d) (%d)\n",
i, _evapi_clients[i].src_addr, _evapi_clients[i].src_port,
(int)rlen, rbuffer);
(int)rlen, _evapi_clients[i].rbuffer+_evapi_clients[i].rpos,
(int)rlen, (int)_evapi_clients[i].rpos);
evenv.conidx = i;
evenv.eset = 1;
if(_evapi_netstring_format) {
/* netstring decapsulation */
k = 0;
while(k<rlen) {
while(k<_evapi_clients[i].rpos+rlen) {
frame.len = 0;
while(k<rlen) {
if(rbuffer[k]==' ' || rbuffer[k]=='\t'
|| rbuffer[k]=='\r' || rbuffer[k]=='\n')
while(k<_evapi_clients[i].rpos+rlen) {
if(_evapi_clients[i].rbuffer[k]==' '
|| _evapi_clients[i].rbuffer[k]=='\t'
|| _evapi_clients[i].rbuffer[k]=='\r'
|| _evapi_clients[i].rbuffer[k]=='\n')
k++;
else break;
}
if(k==rlen) return;
while(k<rlen) {
if(rbuffer[k]>='0' && rbuffer[k]<='9') {
frame.len = frame.len*10 + rbuffer[k] - '0';
if(k==_evapi_clients[i].rpos+rlen) {
_evapi_clients[i].rpos = 0;
LM_DBG("empty content\n");
return;
}
/* pointer to start of whole frame */
sfp = _evapi_clients[i].rbuffer + k;
while(k<_evapi_clients[i].rpos+rlen) {
if(_evapi_clients[i].rbuffer[k]>='0' && _evapi_clients[i].rbuffer[k]<='9') {
frame.len = frame.len*10 + _evapi_clients[i].rbuffer[k] - '0';
} else {
if(rbuffer[k]==':')
if(_evapi_clients[i].rbuffer[k]==':')
break;
/* invalid character - discard the rest */
_evapi_clients[i].rpos = 0;
LM_DBG("invalid char when searching for size [%c] [%.*s] (%d) (%d)\n",
_evapi_clients[i].rbuffer[k],
(int)(_evapi_clients[i].rpos+rlen), _evapi_clients[i].rbuffer,
(int)(_evapi_clients[i].rpos+rlen), k);
return;
}
k++;
}
if(k==rlen || frame.len<=0) return;
if(frame.len + k>=rlen) return;
if(k==_evapi_clients[i].rpos+rlen || frame.len<=0) {
LM_DBG("invalid frame len: %d kpos: %d rpos: %u rlen: %lu\n",
frame.len, k, _evapi_clients[i].rpos, rlen);
_evapi_clients[i].rpos = 0;
return;
}
if(frame.len + k>=_evapi_clients[i].rpos + rlen) {
/* partial data - shift back in buffer and wait to read more */
efp = _evapi_clients[i].rbuffer + _evapi_clients[i].rpos + rlen;
if(efp<=sfp) {
_evapi_clients[i].rpos = 0;
LM_DBG("weird - invalid size for residual data\n");
return;
}
_evapi_clients[i].rpos = (unsigned int)(efp-sfp);
if(efp-sfp > sfp-_evapi_clients[i].rbuffer) {
memcpy(_evapi_clients[i].rbuffer, sfp, _evapi_clients[i].rpos);
} else {
for(k=0; k<_evapi_clients[i].rpos; k++) {
_evapi_clients[i].rbuffer[k] = sfp[k];
}
}
LM_DBG("residual data [%.*s] (%d)\n",
_evapi_clients[i].rpos, _evapi_clients[i].rbuffer,
_evapi_clients[i].rpos);
return;
}
k++;
frame.s = rbuffer + k;
if(frame.s[frame.len]!=',') return;
frame.s = _evapi_clients[i].rbuffer + k;
if(frame.s[frame.len]!=',') {
/* invalid data - discard and reset buffer */
LM_DBG("frame size mismatch the ending char (%c): [%.*s] (%d)\n",
frame.s[frame.len], frame.len, frame.s, frame.len);
_evapi_clients[i].rpos = 0 ;
return;
}
frame.s[frame.len] = '\0';
k += frame.len ;
evenv.msg.s = frame.s;
evenv.msg.len = frame.len;
LM_DBG("executing event route for frame: [%.*s] (%d)\n",
frame.len, frame.s, frame.len);
evapi_run_cfg_route(&evenv, _evapi_rts.msg_received);
k++;
}
} else {
evenv.msg.s = rbuffer;
evenv.msg.s = _evapi_clients[i].rbuffer;
evenv.msg.len = rlen;
evapi_run_cfg_route(&evenv, _evapi_rts.msg_received);
}
@ -342,6 +402,8 @@ void evapi_accept_client(struct ev_loop *loop, struct ev_io *watcher, int revent
return;
}
cfg_update();
/* accept new client connection */
csock = accept(watcher->fd, (struct sockaddr *)&caddr, &clen);
@ -417,6 +479,8 @@ void evapi_recv_notify(struct ev_loop *loop, struct ev_io *watcher, int revents)
return;
}
cfg_update();
/* read message from client */
rlen = read(watcher->fd, &sbuf, sizeof(str*));

@ -422,7 +422,7 @@ int geoip_update_pv(str *tomatch, str *name)
}
strncpy(gr->tomatch, tomatch->s, tomatch->len);
tomatch->s[tomatch->len] = '\0';
gr->tomatch[tomatch->len] = '\0';
gr->record = GeoIP_record_by_name(_handle_GeoIP,
(const char*)gr->tomatch);
LM_DBG("attempt to match: %s\n", gr->tomatch);

@ -460,7 +460,10 @@ int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode)
}
cell->next = it->next;
cell->prev = it->prev;
cell->expire = now + ht->htexpire;
if(ht->updateexpire)
cell->expire = now + ht->htexpire;
else
cell->expire = it->expire;
if(it->prev)
it->prev->next = cell;
else
@ -489,7 +492,10 @@ int ht_set_cell(ht_t *ht, str *name, int type, int_str *val, int mode)
if(mode) ht_slot_unlock(ht, idx);
return -1;
}
cell->expire = now + ht->htexpire;
if(ht->updateexpire)
cell->expire = now + ht->htexpire;
else
cell->expire = it->expire;
cell->next = it->next;
cell->prev = it->prev;
if(it->prev)
@ -649,7 +655,8 @@ ht_cell_t* ht_cell_value_add(ht_t *ht, str *name, int val, int mode,
return NULL;
} else {
it->value.n += val;
it->expire = now + ht->htexpire;
if(ht->updateexpire)
it->expire = now + ht->htexpire;
if(old!=NULL)
{
if(old->msize>=it->msize)

@ -393,13 +393,10 @@ int pv_get_ht_expired_cell(struct sip_msg *msg, pv_param_t *param,
strncmp(param->pvn.u.isname.name.s.s, "value", 5) == 0)
{
if(ht_expired_cell->flags&AVP_VAL_STR) {
res->rs = ht_expired_cell->value.s;
res->flags = PV_VAL_STR;
return pv_get_strval(msg, param, res, &ht_expired_cell->value.s);
} else {
res->ri = ht_expired_cell->value.n;
res->flags = PV_VAL_INT|PV_TYPE_INT;
return pv_get_sintval(msg, param, res, ht_expired_cell->value.n);
}
return 0;
}
if (res->rs.s == NULL)

@ -1042,7 +1042,7 @@ static void htable_rpc_list(rpc_t* rpc, void* c)
if (ht->dbtable.len > 0) {
len = ht->dbtable.len > 127 ? 127 : ht->dbtable.len;
memcpy(dbname, ht->dbtable.s, len);
dbname[ht->dbtable.len] = '\0';
dbname[len] = '\0';
} else {
dbname[0] = '\0';
}

@ -0,0 +1,818 @@
IMS Usrloc PCSCF Module
Jason Penton
Smile Communications
Edited by
Richard Good
Smile Communications
Copyright © 2012 Smile Communications
__________________________________________________________________
Table of Contents
1. Admin Guide
1. Overview
2. Dependencies
2.1. Kamailio Modules
2.2. External Libraries or Applications
3. Parameters
3.1. default_expires (int)
3.2. default_expires_range (int)
3.3. min_expires (int)
3.4. max_expires (int)
3.5. subscription_default_expires (int)
3.6. subscription_expires_range (int)
3.7. subscription_min_expires (int)
3.8. subscription_max_expires (int)
3.9. user_data_dtd (string)
3.10. user_data_xsd (string)
3.11. support_wildcardPSI (int)
3.12. scscf_name (string)
3.13. store_profile_dereg (int)
3.14. cxdx_dest_realm (string)
3.15. cxdx_forced_peer (string)
3.16. append_branches (integer)
3.17. method_filtering (integer)
3.18. user_data_always (integer)
4. Functions
4.1. save(async_reply_route, domain)
4.2. lookup(domain)
4.3. lookup_path_to_contact(uri)
4.4. unregister(domain)
4.5. assign_server_unreg(aysnc_reply_route, domain,
direction)
4.6. impu_registered(domain)
4.7. term_impu_registered(domain)
4.8. reg_fetch_contacts(domain, uri, profile)
4.9. reg_free_contacts(profile)
4.10. can_subscribe_to_reg(domain)
4.11. subscribe_to_reg(domain)
4.12. can_publish_reg(domain)
4.13. publish_reg(domain)
5. RPC Commands
5.1. ulpcscf.status
6. Statistics
6.1. registered contacts
6.2. impus
6.3. expired contacts
2. Frequently Asked Questions
List of Examples
1.1. Set default_expires parameter
1.2. Set default_expires_range parameter
1.3. Set min_expiresparameter
1.4. Set max_expiresparameter
1.5. Set subscription_default_expires parameter
1.6. Set subscription_expires_range parameter
1.7. Set subscription_min_expiresparameter
1.8. Set subscription_max_expiresparameter
1.9. Set user_data_dtdparameter
1.10. Set user_data_xsdparameter
1.11. Set support_wildcardPSIparameter
1.12. Set scscf_nameparameter
1.13. Set store_profile_deregparameter
1.14. Set cxdx_dest_realmparameter
1.15. Set cxdx_forced_peerparameter
1.16. Set cxdx_forced_peerparameter
1.17. Set cxdx_forced_peerparameter
1.18. Set user_data_alwaysparameter
1.19. save usage
1.20. lookup usage
1.21. lookup usage
1.22. unregister usage
1.23. impu_registered usage
1.24. term_impu_registered usage
1.25. reg_fetch_contacts usage
1.26. reg_free_contacts usage
1.27. can_subscribe_to_reg usage
1.28. subscribe_to_reg usage
1.29. can_publish_reg usage
1.30. publish_reg usage
Chapter 1. Admin Guide
Table of Contents
1. Overview
2. Dependencies
2.1. Kamailio Modules
2.2. External Libraries or Applications
3. Parameters
3.1. default_expires (int)
3.2. default_expires_range (int)
3.3. min_expires (int)
3.4. max_expires (int)
3.5. subscription_default_expires (int)
3.6. subscription_expires_range (int)
3.7. subscription_min_expires (int)
3.8. subscription_max_expires (int)
3.9. user_data_dtd (string)
3.10. user_data_xsd (string)
3.11. support_wildcardPSI (int)
3.12. scscf_name (string)
3.13. store_profile_dereg (int)
3.14. cxdx_dest_realm (string)
3.15. cxdx_forced_peer (string)
3.16. append_branches (integer)
3.17. method_filtering (integer)
3.18. user_data_always (integer)
4. Functions
4.1. save(async_reply_route, domain)
4.2. lookup(domain)
4.3. lookup_path_to_contact(uri)
4.4. unregister(domain)
4.5. assign_server_unreg(aysnc_reply_route, domain, direction)
4.6. impu_registered(domain)
4.7. term_impu_registered(domain)
4.8. reg_fetch_contacts(domain, uri, profile)
4.9. reg_free_contacts(profile)
4.10. can_subscribe_to_reg(domain)
4.11. subscribe_to_reg(domain)
4.12. can_publish_reg(domain)
4.13. publish_reg(domain)
5. RPC Commands
5.1. ulpcscf.status
6. Statistics
6.1. registered contacts
6.2. impus
6.3. expired contacts
1. Overview
This module contains REGISTER processing logic for the S-CSCF. The
'storage engine' of this module is provided by the ims_usrloc_scscf
module:
2. Dependencies
2.1. Kamailio Modules
2.2. External Libraries or Applications
2.1. Kamailio Modules
The following modules must be loaded before this module:
* CDP
* CDP_AVP
* TM
* ims_usrloc_scscf
2.2. External Libraries or Applications
The following libraries or applications must be installed before
running Kamailio with this module loaded:
* LibXML2 - used for parsing the XML Subscription information
obtained from the HSS (Home Subscriber Server)
3. Parameters
3.1. default_expires (int)
3.2. default_expires_range (int)
3.3. min_expires (int)
3.4. max_expires (int)
3.5. subscription_default_expires (int)
3.6. subscription_expires_range (int)
3.7. subscription_min_expires (int)
3.8. subscription_max_expires (int)
3.9. user_data_dtd (string)
3.10. user_data_xsd (string)
3.11. support_wildcardPSI (int)
3.12. scscf_name (string)
3.13. store_profile_dereg (int)
3.14. cxdx_dest_realm (string)
3.15. cxdx_forced_peer (string)
3.16. append_branches (integer)
3.17. method_filtering (integer)
3.18. user_data_always (integer)
3.1. default_expires (int)
If the processed message contains neither Expires HFs nor expires
contact parameters, this value will be used for newly created S-CSCF
usrloc records. The parameter contains number of second to expire (for
example use 3600 for one hour). If it is set to a lower value than the
min_expires parameter then it will be ignored. This parameter can be
modified via ser config framework. A random value in a specific
interval can be selected by using the default_expires_range parameter
Default value is 3600.
Example 1.1. Set default_expires parameter
...
modparam("ims_registrar_scscf", "default_expires", 3600)
...
3.2. default_expires_range (int)
This parameter specifies that the expiry used for newly created S-CSCF
usrloc records are not fixed(when default_expires applies), but a
random value in the intervalrdq
[default_expires-default_expires_range%,
default_expires+default_expires_range%]. The value is between 0 and 100
and represent the maximim percentage from default_expires that will be
substracted or added when computing the value. Default in 0, meaning
default_expires is left unmodified. This parameter can be modified via
ser config framework.
Default value is 0.
Example 1.2. Set default_expires_range parameter
...
modparam("ims_registrar_scscf", "default_expires_range", 30) # +- 30% fr
om default_expires
...
3.3. min_expires (int)
The minimum expires value of a Contact, values lower than this minimum
will be automatically set to the minimum. Value 0 disables the
checking. This parameter can be modified via ser config framework.
Default value is 60.
Example 1.3. Set min_expiresparameter
...
modparam("ims_registrar_scscf", "min_expires", 1800)
...
3.4. max_expires (int)
The maximum expires value of a Contact, values higher than this maximum
will be automatically set to the maximum. Value 0 disables the
checking. This parameter can be modified via ser config framework.
Default value is 0.
Example 1.4. Set max_expiresparameter
...
modparam("ims_registrar_scscf", "max_expires", 3600)
...
3.5. subscription_default_expires (int)
If the processed message contains neither Expires HFs nor expires
contact parameters, this value will be used for newly created
subscriptions. The parameter contains number of second to expire (for
example use 3600 for one hour). If it is set to a lower value than the
subscription_min_expires parameter then it will be ignored. A random
value in a specific interval can be selected by using the
subscription_expires_range parameter
Default value is 3600.
Example 1.5. Set subscription_default_expires parameter
...
modparam("ims_registrar_scscf", "subscription_default_expires", 3600)
...
3.6. subscription_expires_range (int)
This parameter specifies that the expiry used for newly created
subscriptions are not fixed(when subscription_default_expires applies),
but a random value in the interval
[subscription_default_expires-subscription_expires_range%,
subscription_default_expires+subscription_expires_range%]. The value is
between 0 and 100 and represent the maximim percentage from
subscription_default_expires that will be substracted or added when
computing the value. Default in 0, meaning subscription_default_expires
is left unmodified.
Default value is 0.
Example 1.6. Set subscription_expires_range parameter
...
modparam("ims_registrar_scscf", "subscription_expires_range", 30) # +- 3
0% from subscription_expires_range
...
3.7. subscription_min_expires (int)
The minimum expires value of a subscription, values lower than this
minimum will be automatically set to the minimum. Value 0 disables the
checking.
Default value is 10.
Example 1.7. Set subscription_min_expiresparameter
...
modparam("subscription_min_expires", "min_expires", 1800)
...
3.8. subscription_max_expires (int)
The maximum expires value of a subscription, values higher than this
maximum will be automatically set to the maximum. Value 0 disables the
checking.
Default value is 1000000.
Example 1.8. Set subscription_max_expiresparameter
...
modparam("ims_registrar_scscf", "subscription_max_expires", 3600)
...
3.9. user_data_dtd (string)
DTD to check the user data received in SAA (Server Assignment Answer).
Default value is NULL (none).
Example 1.9. Set user_data_dtdparameter
...
modparam("ims_registrar_scscf", "user_data_dtd", "/usr/local/etc/kamaili
o/CxDataType_Rel7.dtd")
...
3.10. user_data_xsd (string)
XSD to check the user data received in SAA (Server Assignment Answer).
Default value is NULL (none).
Example 1.10. Set user_data_xsdparameter
...
modparam("ims_registrar_scscf", "user_data_xsd", "/usr/local/etc/kamaili
o/CxDataType_Rel7.xsd")
...
3.11. support_wildcardPSI (int)
indicate support for wildcard PSI is subscription profile (SAA)
Default value is 0.
Example 1.11. Set support_wildcardPSIparameter
...
modparam("ims_registrar_scscf", "support_wildcardPSI", 1)
...
3.12. scscf_name (string)
The name of the S-CSCF
Default value is sip:scscf.ims.smilecoms.com:6060.
Example 1.12. Set scscf_nameparameter
...
modparam("ims_registrar_scscf", "scscf_name", "sip:scscf2.ims.smilecoms.
com:6060")
...
3.13. store_profile_dereg (int)
Should the subscription profile be stored on de-registration
Default value 0.
Example 1.13. Set store_profile_deregparameter
...
modparam("ims_registrar_scscf", "store_profile_dereg", 1)
...
3.14. cxdx_dest_realm (string)
Destination realm to be used in Diameter messages
Default value "ims.smilecoms.com"
Example 1.14. Set cxdx_dest_realmparameter
...
modparam("ims_registrar_scscf", "cxdx_dest_realm", "my.domain,org")
...
3.15. cxdx_forced_peer (string)
FQDN of Diameter Peer (HSS) to use for communication (SAR). If you use
this, the routing defined in your diameter xml configuration file (CDP)
will be ignored and as a result you will lose the benefits of load
balancing and failover.
Default value NULL (none)
Example 1.15. Set cxdx_forced_peerparameter
...
modparam("ims_registrar_scscf", "cxdx_forced_peer", "hss.ims.smilecoms.c
om")
...
3.16. append_branches (integer)
The parameter controls how lookup function processes multiple contacts.
If there are multiple contacts for the given username in usrloc and
this parameter is set to 1, Request-URI will be overwritten with the
highest-q rated contact and the rest will be appended to sip_msg
structure and can be later used by tm for forking. If the parameter is
set to 0, only Request-URI will be overwritten with the highest-q rated
contact and the rest will be left unprocessed. This parameter can be
modified via Kamailio config framework.
Default value is 0 (disabled)
Example 1.16. Set cxdx_forced_peerparameter
...
modparam("ims_registrar_scscf", "append_branches", 1)
...
3.17. method_filtering (integer)
Tells if the contact filtering based on supported methods should be
performed during lookup. It's enabled only if it has a non zero value.
Default value is 0 (disabled)
Example 1.17. Set cxdx_forced_peerparameter
...
modparam("ims_registrar_scscf", "method_filtering", 1)
...
3.18. user_data_always (integer)
If specified this will make the S-CSCF always request user data from
HSS.
Default value is 0 (disabled)
Example 1.18. Set user_data_alwaysparameter
...
modparam("ims_registrar_scscf", "user_data_always", 1)
...
4. Functions
4.1. save(async_reply_route, domain)
4.2. lookup(domain)
4.3. lookup_path_to_contact(uri)
4.4. unregister(domain)
4.5. assign_server_unreg(aysnc_reply_route, domain, direction)
4.6. impu_registered(domain)
4.7. term_impu_registered(domain)
4.8. reg_fetch_contacts(domain, uri, profile)
4.9. reg_free_contacts(profile)
4.10. can_subscribe_to_reg(domain)
4.11. subscribe_to_reg(domain)
4.12. can_publish_reg(domain)
4.13. publish_reg(domain)
4.1. save(async_reply_route, domain)
The function processes a REGISTER message. It can add, remove or modify
usrloc records depending on Contact and Expires HFs in the REGISTER
message. On success and when called from the REQUEST_ROUTE, 200 OK will
be returned listing all contacts that are currently in usrloc. On an
error, error message will be sent with a short description in reason
phrase. In case of internal errors the function will return FALSE,
otherwise a force to exit the cfg is file is actioned by returning 0
(asynchronous processing)
Meaning of the parameters is as follows:
* async_reply_route- the route to execute after the save has
completed. This is required because the save function is executed
asynchronously (Diameter).
* domain- Logical domain within registrar.
This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE
Example 1.19. save usage
...
if (!impu_registered("location")) {
save("PRE_REG_SAR_REPLY","location");
}
...
4.2. lookup(domain)
This function extract the IMPU from the Request-URI and tries to find
all registered contacts in usrloc. If there are no such contacts, -1 is
returned. If there are, Request-URI will be rewritten with the contact
that has the highest q value. The rest of the contacts will be appended
to the sip msg structure (if append_branches is set) and can be later
used by TM module for forking for example...
If the method filtering option is enabled, the lookup function will
only return contacts that support the method of the request being
processed (see allows header)
Meaning of the parameters is as follows:
* domain - Logical domain within registrar.
Return codes:
* -1 - Not found
* -2 - Found, but method not allowed (check Allows header for INVITE,
MESSAGE, etc).
* -3 - Error ocurred internally during processing
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE
Example 1.20. lookup usage
...
lookup("location");
switch ($retcode) {
case -1:
case -3:
sl_send_reply("404", "Not Found");
exit;
case -2:
sl_send_reply("405", "Not Found");
exit;
};
...
4.3. lookup_path_to_contact(uri)
This function take a URI and tries to find the contact in usrloc. If
the contact is found and has a path set, then a path header is added to
the SIP message so it can be loose routed.
Meaning of the parameters is as follows:
* uri - URI of contact to lookup
Return codes:
* 1 - Success
* -1 - Failure
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE
Example 1.21. lookup usage
...
lookup_path_to_contact($ruri);
...
4.4. unregister(domain)
This function will remove all bindings for the IMPU found in the
Request-URI.
Meaning of the parameters is as follows:
* Domain- Logical domain within registrar.
This function can be used in REQUEST_ROUTE, FAILURE_ROUTE
Example 1.22. unregister usage
...
unregister("location");
...
4.5. assign_server_unreg(aysnc_reply_route, domain, direction)
TBD
used in REQUEST_ROUTE
4.6. impu_registered(domain)
This function checks if the IMPU in the To header is registered in
usrloc.
Meaning of the parameters is as follows:
* domain- Logical domain within registrar.
Return codes:
* 1 - True, IMPU exists in registered state in usrloc
* -1 - False, IMPU not registered
This function can be used in REQUEST_ROUTE, FAILURE_ROUTE
Example 1.23. impu_registered usage
...
impu_registered("location");
switch ($retcode) {
case -1:
sl_send_reply("404", "Not Found");
exit;
case 1:
#true, continue with normal processing
};
...
4.7. term_impu_registered(domain)
This function checks if the IMPU in the Request-URI is registered in
usrloc.
Meaning of the parameters is as follows:
* domain- Logical domain within registrar.
Return codes:
* 1 - True, IMPU exists in registered state in usrloc
* -1 - False, IMPU not registered
This function can be used in REQUEST_ROUTE, FAILURE_ROUTE
Example 1.24. term_impu_registered usage
...
term_impu_registered("location");
switch ($retcode) {
case -1:
sl_send_reply("404", "Not Found");
exit;
case 1:
#true, continue with normal processing
};
...
4.8. reg_fetch_contacts(domain, uri, profile)
The function fetches the contacts for 'uri' from table 'domain' to
pseudo-variable $imssulc(profile) [imssulc = ims scscf ulc].
Meaning of the parameters is as follows:
* domain - Name of table that should be used for the lookup of
contact addresses.
* uri - The SIP URI address of the user which to fetch the contact
addresses for. It can contain pseudo-variables that are evaluated
at runtime.
* profile - Name of $imssulc pseudo-variable profile that will store
the fetched contacts. It is a static string.
This function can be used in REQUEST_ROUTE, FAILURE_ROUTE
Example 1.25. reg_fetch_contacts usage
...
reg_fetch_contacts("location", "$ru", "callee");
reg_fetch_contacts("location", "sip:user@kamailio.org", "caller");
...
4.9. reg_free_contacts(profile)
The function frees the contacts from pseudo-variable $ulc(profile).
Should be called to release the content of a profile. Anyhow, fetching
a new contact addresses set over a profile will release any existing
data in that profile.
Meaning of the parameters is as follows:
* profile - Name of $imssulc pseudo-variable profile that stores the
contacts. It is a static string.
This function can be used in REQUEST_ROUTE, FAILURE_ROUTE
Example 1.26. reg_free_contacts usage
...
reg_free_contacts("callee");
...
4.10. can_subscribe_to_reg(domain)
This function checks to see that a SUBSCRIBE request is authorised to
subscribe to the particular identity. Only 3 entities can subscribe:
* The user agent to it's own state
* The P-CSCF specified in the path header for that user
* Application Server (AS) not yet implemented
Meaning of the parameters is as follows:
* domain - Logical domain within registrar.
This function can be used in REQUEST_ROUTE
Example 1.27. can_subscribe_to_reg usage
...
if (can_subscribe_to_reg("location")){
$var(ret)= subscribe_to_reg("location");
}
...
4.11. subscribe_to_reg(domain)
Save the subscription to the REG event for the UAC or the appropriate
P-CSCF (in the path to the UAC).
Meaning of the parameters is as follows:
* domain - Logical domain within registrar.
This function can be used in REQUEST_ROUTE
Example 1.28. subscribe_to_reg usage
...
if (can_subscribe_to_reg("location")){
$var(ret)= subscribe_to_reg("location");
}
...
4.12. can_publish_reg(domain)
This function checks to see that a PUBLISH request is authorised to
publish for a particular identity. Only 3 entities can publish:
* The user agent to it's own state
* The P-CSCF specified in the path header for that user
* Application Server (AS) not yet implemented
Meaning of the parameters is as follows:
* domain - Logical domain within registrar.
This function can be used in REQUEST_ROUTE
Example 1.29. can_publish_reg usage
...
if (can_publish_reg("location")){
$var(ret)= publish_reg("location");
}
...
4.13. publish_reg(domain)
Save the publish to the REG event for the UAC or the appropriate P-CSCF
(in the path to the UAC).
Meaning of the parameters is as follows:
* domain - Logical domain within registrar.
This function can be used in REQUEST_ROUTE
Example 1.30. publish_reg usage
...
if (can_publish_reg("location")){
$var(ret)= publish_reg("location");
}
...
5. RPC Commands
5.1. ulpcscf.status
exported RPC commands.
5.1. ulpcscf.status
Status of pcscf_usrloc, AORs, max slots, etc.
6. Statistics
6.1. registered contacts
6.2. impus
6.3. expired contacts
Exported statistics are listed in the next sections.
6.1. registered contacts
Number of AOR contacts in registered state - cannot be reset.
6.2. impus
Number of IMPUs - cannot be reset.
6.3. expired contacts
Number of expired contacts - can be reset.
Chapter 2. Frequently Asked Questions
2.1. Where can I find more about Kamailio?
2.2. Where can I post a question about this module?
2.3. How can I report a bug?
2.1.
Where can I find more about Kamailio?
Take a look at http://www.kamailio.org/.
2.2.
Where can I post a question about this module?
First at all check if your question was already answered on one of our
mailing lists:
* User Mailing List -
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
* Developer Mailing List -
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
E-mails regarding any stable Kamailio release should be sent to
<sr-users@lists.sip-router.org> and e-mails regarding development
versions should be sent to <sr-dev@lists.sip-router.org>.
If you want to keep the mail private, send it to
<sr-users@lists.sip-router.org>.
2.3.
How can I report a bug?
Please follow the guidelines provided at:
http://sip-router.org/tracker.

@ -453,10 +453,10 @@ if (srv_query ("_sip._udp.example.com", "udp") > 0) {
$var(cnt) = $srvquery(udp=>count);
$var(i) = 0;
while ($var(i) < $var(cnt)) {
xlog ("port[$var(i)] $srvquery(udp=>port[$var(i)])\n)";
xlog ("priority[$var(i)] $srvquery(udp=>priority[$var(i)])\n)";
xlog ("target[$var(i)] $srvquery(udp=>target[$var(i)])\n)";
xlog ("weight[$var(i)] $srvquery(udp=>weight[$var(i)])\n)";
xlog ("port[$var(i)] $srvquery(udp=>port[$var(i)])\n");
xlog ("priority[$var(i)] $srvquery(udp=>priority[$var(i)])\n");
xlog ("target[$var(i)] $srvquery(udp=>target[$var(i)])\n");
xlog ("weight[$var(i)] $srvquery(udp=>weight[$var(i)])\n");
$var(i) = $var(i) + 1;
}
}

@ -752,10 +752,10 @@ if (srv_query ("_sip._udp.example.com", "udp") > 0) {
$var(cnt) = $srvquery(udp=>count);
$var(i) = 0;
while ($var(i) &lt; $var(cnt)) {
xlog ("port[$var(i)] $srvquery(udp=>port[$var(i)])\n)";
xlog ("priority[$var(i)] $srvquery(udp=>priority[$var(i)])\n)";
xlog ("target[$var(i)] $srvquery(udp=>target[$var(i)])\n)";
xlog ("weight[$var(i)] $srvquery(udp=>weight[$var(i)])\n)";
xlog ("port[$var(i)] $srvquery(udp=>port[$var(i)])\n");
xlog ("priority[$var(i)] $srvquery(udp=>priority[$var(i)])\n");
xlog ("target[$var(i)] $srvquery(udp=>target[$var(i)])\n");
xlog ("weight[$var(i)] $srvquery(udp=>weight[$var(i)])\n");
$var(i) = $var(i) + 1;
}
}

@ -308,12 +308,12 @@ E;retry=1");
}
route[RESPONSE] {
if(jansson_get($var(jsrpc_result), "internal_error", "$var(internal)"))
if(jansson_get("internal_error", $var(jsrpc_result), "$var(internal)"))
{
route(INTERNAL);
} else if(jansson_get($var(jsrpc_result), "error", "$var(error)")) {
} else if(jansson_get("error", $var(jsrpc_result), "$var(error)")) {
route(ERROR);
} else if(jansson_get($var(jsrpc_result), "result", "$var(result)")) {
} else if(jansson_get("result", $var(jsrpc_result), "$var(result)")) {
route(RESULT);
}
t_reply("200", "OK");
@ -326,15 +326,15 @@ route[RESULT] {
route[ERROR] {
xlog("There was an error\n");
if(jansson_get($var(error), "code", "$var(c)")) {
if(jansson_get("code", $var(error), "$var(c)")) {
xlog("code is $var(c)\n");
}
if(jansson_get($var(error), "message", "$var(r)")) {
if(jansson_get("message", $var(error), "$var(r)")) {
xlog("error is $var(r)\n");
}
if(jansson_get($var(error), "data", "$var(d)")) {
if(jansson_get("data", $var(error), "$var(d)")) {
xlog("data is $var(d)\n");
}
}
@ -342,13 +342,13 @@ route[ERROR] {
route[INTERNAL] {
xlog("There was an internal error\n");
jansson_get($var(internal), "code", "$var(c)");
jansson_get("code", $var(internal), "$var(c)");
xlog("code is $var(c)\n");
jansson_get($var(internal), "message", "$var(r)");
jansson_get("message", $var(internal), "$var(r)");
xlog("error is $var(r)\n");
if(jansson_get($var(internal), "data", "$var(d)")) {
if(jansson_get("data", $var(internal), "$var(d)")) {
xlog("request is $var(d)\n");
}
}

@ -356,11 +356,11 @@ route {
}
route[RESPONSE] {
if(jansson_get($var(jsrpc_result), "internal_error", "$var(internal)")) {
if(jansson_get("internal_error", $var(jsrpc_result), "$var(internal)")) {
route(INTERNAL);
} else if(jansson_get($var(jsrpc_result), "error", "$var(error)")) {
} else if(jansson_get("error", $var(jsrpc_result), "$var(error)")) {
route(ERROR);
} else if(jansson_get($var(jsrpc_result), "result", "$var(result)")) {
} else if(jansson_get("result", $var(jsrpc_result), "$var(result)")) {
route(RESULT);
}
t_reply("200", "OK");
@ -373,15 +373,15 @@ route[RESULT] {
route[ERROR] {
xlog("There was an error\n");
if(jansson_get($var(error), "code", "$var(c)")) {
if(jansson_get("code", $var(error), "$var(c)")) {
xlog("code is $var(c)\n");
}
if(jansson_get($var(error), "message", "$var(r)")) {
if(jansson_get("message", $var(error), "$var(r)")) {
xlog("error is $var(r)\n");
}
if(jansson_get($var(error), "data", "$var(d)")) {
if(jansson_get("data", $var(error), "$var(d)")) {
xlog("data is $var(d)\n");
}
}
@ -389,13 +389,13 @@ route[ERROR] {
route[INTERNAL] {
xlog("There was an internal error\n");
jansson_get($var(internal), "code", "$var(c)");
jansson_get("code", $var(internal), "$var(c)");
xlog("code is $var(c)\n");
jansson_get($var(internal), "message", "$var(r)");
jansson_get("message", $var(internal), "$var(r)");
xlog("error is $var(r)\n");
if(jansson_get($var(internal), "data", "$var(d)")) {
if(jansson_get("data", $var(internal), "$var(d)")) {
xlog("request is $var(d)\n");
}
}

@ -88,9 +88,13 @@ void force_disconnect(jsonrpc_server_t* server)
/* clean out requests */
jsonrpc_request_t* req = NULL;
jsonrpc_request_t* next = NULL;
int key = 0;
for (key=0; key < JSONRPC_DEFAULT_HTABLE_SIZE; key++) {
for (req = request_table[key]; req != NULL; req = req->next) {
for (req = request_table[key]; req != NULL; req = next) {
/* fail_request frees req so need to store
next_req before call */
next = req->next;
if(req->server != NULL && req->server == server) {
fail_request(JRPC_ERR_SERVER_DISCONNECT, req,
"Failing request for server shutdown");
@ -128,9 +132,10 @@ void server_backoff_cb(int fd, short event, void *arg)
close(fd);
CHECK_AND_FREE_EV(a->ev);
pkg_free(arg);
wait_server_backoff(timeout, a->server, false);
pkg_free(arg);
}
void wait_server_backoff(unsigned int timeout /* seconds */,

@ -587,9 +587,12 @@ int handle_response(json_t* response)
return_obj = json_object();
json_t* error = json_object_get(response, "error");
// if the error value is null, we don't care
bool _error = error && (json_typeof(error) != JSON_NULL);
json_t* result = json_object_get(response, "result");
if(error) {
if(_error) {
json_object_set(return_obj, "error", error);
}
@ -597,7 +600,7 @@ int handle_response(json_t* response)
json_object_set(return_obj, "result", result);
}
if ((!result && !error) || (result && error)) {
if ((!result && !_error) || (result && _error)) {
WARN("bad response\n");
internal = internal_error(JRPC_ERR_BAD_RESP, req->payload);
json_object_update(return_obj, internal);
@ -621,7 +624,7 @@ int handle_response(json_t* response)
goto free_and_end;
}
if(error) {
if(_error) {
// get code from error
json_t* _code = json_object_get(error, "code");
if(_code) {

@ -253,8 +253,6 @@ int schedule_retry(jsonrpc_request_t* req)
new_req->ntries = req->ntries;
free_request(req);
const struct timeval tv = ms_to_tv(time);
new_req->retry_ev = evtimer_new(global_ev_base, retry_cb, (void*)new_req);
@ -264,6 +262,8 @@ int schedule_retry(jsonrpc_request_t* req)
goto error;
}
free_request(req);
return 0;
error:
ERR("schedule_retry failed.\n");

@ -591,8 +591,10 @@ void free_server_list(server_list_t* list)
return;
server_list_t* node = NULL;
for(node=list; node!=NULL; node=node->next)
server_list_t* next = NULL;
for(node=list; node!=NULL; node=next)
{
next = node->next;
pkg_free(node);
}
}

@ -142,6 +142,11 @@ int (*res_cb)(json_object*, char*, int) = &result_cb;
void cmd_pipe_cb(int fd, short event, void *arg)
{
struct jsonrpc_pipe_cmd *cmd;
char *ns = 0;
size_t bytes;
json_object *payload = NULL;
jsonrpc_request_t *req = NULL;
json_object *params;
/* struct event *ev = (struct event*)arg; */
if (read(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
@ -149,9 +154,7 @@ void cmd_pipe_cb(int fd, short event, void *arg)
return;
}
json_object *params = json_tokener_parse(cmd->params);
json_object *payload = NULL;
jsonrpc_request_t *req = NULL;
params = json_tokener_parse(cmd->params);
if (cmd->notify_only) {
payload = build_jsonrpc_notification(cmd->method, params);
@ -163,11 +166,10 @@ void cmd_pipe_cb(int fd, short event, void *arg)
if (!payload) {
LM_ERR("Failed to build jsonrpc_request_t (method: %s, params: %s)\n", cmd->method, cmd->params);
return;
goto error;
}
char *json = (char*)json_object_get_string(payload);
char *ns; size_t bytes;
bytes = netstring_encode_new(&ns, json, (size_t)strlen(json));
struct jsonrpc_server_group *g;
@ -201,7 +203,7 @@ void cmd_pipe_cb(int fd, short event, void *arg)
if (timerfd == -1) {
LM_ERR("Could not create timerfd.");
return;
goto error;
}
req->timerfd = timerfd;
@ -215,7 +217,7 @@ void cmd_pipe_cb(int fd, short event, void *arg)
if (timerfd_settime(timerfd, 0, itime, NULL) == -1)
{
LM_ERR("Could not set timer.");
return;
goto error;
}
pkg_free(itime);
struct event *timer_ev = pkg_malloc(sizeof(struct event));
@ -223,7 +225,7 @@ void cmd_pipe_cb(int fd, short event, void *arg)
event_set(timer_ev, timerfd, EV_READ, timeout_cb, req);
if(event_add(timer_ev, NULL) == -1) {
LM_ERR("event_add failed while setting request timer (%s).", strerror(errno));
return;
goto error;
}
req->timer_ev = timer_ev;
} else if (!sent) {
@ -237,6 +239,14 @@ void cmd_pipe_cb(int fd, short event, void *arg)
pkg_free(ns);
json_object_put(payload);
if (cmd->notify_only) free_pipe_cmd(cmd);
return;
error:
if(ns) pkg_free(ns);
if(payload) json_object_put(payload);
if (cmd->notify_only) free_pipe_cmd(cmd);
return;
}
void socket_cb(int fd, short event, void *arg)
@ -338,6 +348,7 @@ int parse_servers(char *_servers, struct jsonrpc_server_group **group_ptr)
struct jsonrpc_server *server = pkg_malloc(sizeof(struct jsonrpc_server));
CHECK_MALLOC(server);
memset(server, 0, sizeof(struct jsonrpc_server));
char *h = pkg_malloc(strlen(host)+1);
CHECK_MALLOC(h);
@ -365,6 +376,7 @@ int parse_servers(char *_servers, struct jsonrpc_server_group **group_ptr)
selected_group = pkg_malloc(sizeof(struct jsonrpc_server_group));
CHECK_MALLOC(selected_group);
memset(selected_group, 0, sizeof(struct jsonrpc_server_group));
selected_group->priority = priority;
selected_group->next_server = server;

@ -1670,7 +1670,7 @@ error:
return 0;
}
#define JSONRPC_BUF_IN_SIZE 4096
#define JSONRPC_BUF_IN_SIZE 8192
static void jsonrpc_run_fifo_server(FILE *fifo_stream)
{
FILE *reply_stream;

@ -51,7 +51,15 @@
#include "../../cfg/cfg.h"
#include "../../cfg/cfg_ctx.h"
#ifdef VERSION_NODATE
#define BUILD_STR __FILE__ " compiled with " COMPILER "\n"
#else
#ifdef VERSION_DATE
#define BUILD_STR __FILE__ " compiled on " VERSION_DATE " with " COMPILER "\n"
#else
#define BUILD_STR __FILE__ " compiled on "__TIME__ " " __DATE__ " with " COMPILER "\n"
#endif
#endif
#define BUILD_STR_LEN (sizeof(BUILD_STR)-1)
#ifndef SVNREVISION

@ -359,6 +359,7 @@ static void datagram_close_async(struct mi_root *mi_rpl,struct mi_handler *hdl,
}
free_mi_tree(mi_rpl);
pkg_free(dtgram.start);
if (done) free_async_handler( hdl );
} else if (done) {
mi_send_dgram(reply_sock, MI_COMMAND_FAILED, MI_COMMAND_FAILED_LEN,
(struct sockaddr*)&reply_addr, reply_addr_len, mi_socket_timeout);
@ -372,6 +373,7 @@ err:
if(dtgram.start)
pkg_free(dtgram.start);
close(reply_sock);
if (done) free_async_handler( hdl );
return;
}

@ -119,7 +119,7 @@ modparam("mi_rpc","rpc_url","tcp:localhost:2046")
Depending on the version (e.g. mi, mi_dg) it formats the output in a
similar way to the corresponding kamailio mi module:
* mi - uses a special, "pretty" format which generates nicer (more
readable) output when used with sercmd.
readable) output when used with kamcmd.
* mi_dg - uses an output format similar to the kamailio mi_datagram
module.
* mi_fifo - uses an output format similar to the kamailio mi_fifo
@ -135,8 +135,8 @@ modparam("mi_rpc","rpc_url","tcp:localhost:2046")
_parameters_ - the MI command parameters (optional).
Example using 'sercmd':
sercmd> mi uptime
Example using 'kamcmd':
kamcmd> mi uptime
Now:: Thu Sep 24 18:17:15 2009
Up since:: Thu Sep 24 17:35:45 2009
Up time:: 2490 [sec]

@ -96,7 +96,7 @@ modparam("mi_rpc","rpc_url","tcp:localhost:2046")
<listitem>
<function>mi</function> - uses a special, "pretty" format
which generates nicer (more readable) output when used with
sercmd.
kamcmd.
</listitem>
<listitem>
<function>mi_dg</function> - uses an output format similar to
@ -125,10 +125,10 @@ modparam("mi_rpc","rpc_url","tcp:localhost:2046")
(optional).
</para>
<para>
Example using 'sercmd':
Example using 'kamcmd':
</para>
<programlisting format="linespecific">
sercmd> mi uptime
kamcmd> mi uptime
Now:: Thu Sep 24 18:17:15 2009
Up since:: Thu Sep 24 17:35:45 2009
Up time:: 2490 [sec]

@ -480,13 +480,21 @@ int allow_address(struct sip_msg* _msg, char* _addr_group, char* _addr_sp,
}
if ( ipa ) {
if (match_addr_hash_table(*addr_hash_table, addr_group, ipa, port) == 1)
if (addr_hash_table
&& match_addr_hash_table(*addr_hash_table, addr_group,
ipa, port) == 1) {
return 1;
else
return match_subnet_table(*subnet_table, addr_group, ipa, port);
} else {
if(subnet_table) {
return match_subnet_table(*subnet_table, addr_group, ipa, port);
}
}
} else {
return match_domain_name_table(*domain_list_table, addr_group, &ips, port);
if(domain_list_table) {
return match_domain_name_table(*domain_list_table, addr_group, &ips, port);
}
}
return -1;
}
@ -507,14 +515,17 @@ int allow_source_address(struct sip_msg* _msg, char* _addr_group, char* _str2)
LM_DBG("looking for <%u, %x, %u>\n",
addr_group, _msg->rcv.src_ip.u.addr32[0], _msg->rcv.src_port);
if (match_addr_hash_table(*addr_hash_table, addr_group,
&_msg->rcv.src_ip,
_msg->rcv.src_port) == 1)
if (addr_hash_table && match_addr_hash_table(*addr_hash_table, addr_group,
&_msg->rcv.src_ip, _msg->rcv.src_port) == 1) {
return 1;
else
return match_subnet_table(*subnet_table, addr_group,
} else {
if(subnet_table) {
return match_subnet_table(*subnet_table, addr_group,
&_msg->rcv.src_ip,
_msg->rcv.src_port);
}
}
return -1;
}
@ -525,22 +536,24 @@ int allow_source_address(struct sip_msg* _msg, char* _addr_group, char* _str2)
*/
int allow_source_address_group(struct sip_msg* _msg, char* _str1, char* _str2)
{
int group;
int group = -1;
LM_DBG("looking for <%x, %u> in address table\n",
_msg->rcv.src_ip.u.addr32[0], _msg->rcv.src_port);
group = find_group_in_addr_hash_table(*addr_hash_table,
&_msg->rcv.src_ip,
_msg->rcv.src_port);
LM_DBG("Found <%d>\n", group);
if(addr_hash_table) {
group = find_group_in_addr_hash_table(*addr_hash_table,
&_msg->rcv.src_ip, _msg->rcv.src_port);
LM_DBG("Found <%d>\n", group);
if (group != -1) return group;
if (group != -1) return group;
}
LM_DBG("looking for <%x, %u> in subnet table\n",
_msg->rcv.src_ip.u.addr32[0], _msg->rcv.src_port);
group = find_group_in_subnet_table(*subnet_table,
&_msg->rcv.src_ip,
_msg->rcv.src_port);
if(subnet_table) {
group = find_group_in_subnet_table(*subnet_table,
&_msg->rcv.src_ip, _msg->rcv.src_port);
}
LM_DBG("Found <%d>\n", group);
return group;
@ -553,7 +566,7 @@ int allow_source_address_group(struct sip_msg* _msg, char* _str1, char* _str2)
*/
int allow_address_group(struct sip_msg* _msg, char* _addr, char* _port)
{
int group;
int group = -1;
unsigned int port;
str ips;
@ -575,24 +588,30 @@ int allow_address_group(struct sip_msg* _msg, char* _addr, char* _port)
if ( ipa ) {
LM_DBG("looking for <%.*s, %u> in address table\n",
ips.len, ips.s, port);
group = find_group_in_addr_hash_table(*addr_hash_table,
ipa, port);
LM_DBG("Found address in group <%d>\n", group);
if (group != -1) return group;
if(addr_hash_table) {
group = find_group_in_addr_hash_table(*addr_hash_table,
ipa, port);
LM_DBG("Found address in group <%d>\n", group);
LM_DBG("looking for <%.*s, %u> in subnet table\n",
ips.len, ips.s, port);
group = find_group_in_subnet_table(*subnet_table,
ipa, port);
LM_DBG("Found a match of subnet in group <%d>\n", group);
if (group != -1) return group;
}
if(subnet_table) {
LM_DBG("looking for <%.*s, %u> in subnet table\n",
ips.len, ips.s, port);
group = find_group_in_subnet_table(*subnet_table,
ipa, port);
LM_DBG("Found a match of subnet in group <%d>\n", group);
}
} else {
LM_DBG("looking for <%.*s, %u> in domain_name table\n",
ips.len, ips.s, port);
group = find_group_in_domain_name_table(*domain_list_table,
&ips, port);
LM_DBG("Found a match of domain_name in group <%d>\n", group);
if(domain_list_table) {
group = find_group_in_domain_name_table(*domain_list_table,
&ips, port);
LM_DBG("Found a match of domain_name in group <%d>\n", group);
}
}
LM_DBG("Found <%d>\n", group);
return group;
}

@ -92,7 +92,7 @@ struct mi_root* mi_trusted_dump(struct mi_root *cmd_tree, void *param)
void rpc_trusted_dump(rpc_t* rpc, void* c) {
if (hash_table==NULL) {
rpc->fault(c, 500, "Reload failed. No trusted table");
rpc->fault(c, 500, "No trusted table");
return;
}
@ -154,6 +154,10 @@ struct mi_root* mi_address_dump(struct mi_root *cmd_tree, void *param)
*/
void rpc_address_dump(rpc_t* rpc, void* c) {
if(addr_hash_table==NULL) {
rpc->fault(c, 500, "No address table");
return;
}
if(addr_hash_table_rpc_print(*addr_hash_table, rpc, c) < 0 ) {
LM_DBG("failed to print a subnet_table dump\n");
}
@ -185,6 +189,10 @@ struct mi_root* mi_subnet_dump(struct mi_root *cmd_tree, void *param)
* RPC function to dump subnet table
*/
void rpc_subnet_dump(rpc_t* rpc, void* c) {
if(subnet_table==NULL) {
rpc->fault(c, 500, "No subnet table");
return;
}
if(subnet_table_rpc_print(*subnet_table, rpc, c) < 0) {
LM_DBG("failed to print a subnet_table dump\n");
}
@ -217,6 +225,10 @@ struct mi_root* mi_domain_name_dump(struct mi_root *cmd_tree, void *param)
*/
void rpc_domain_name_dump(rpc_t* rpc, void* c) {
if(domain_list_table==NULL) {
rpc->fault(c, 500, "No domain list table");
return;
}
if ( domain_name_table_rpc_print(*domain_list_table, rpc, c) < 0 ) {
LM_DBG("failed to print a subnet_table dump\n");
}

@ -24,6 +24,9 @@ Daniel-Constantin Mierla
1. Admin Guide
1. Overview
1.1. Algorithms
2. Dependencies
2.1. Kamailio Modules
@ -77,7 +80,7 @@ Daniel-Constantin Mierla
1.9. Set reply_code parameter at runtime
1.10. Set reply_reason parameter
1.11. Set reply_reason parameter at runtime
1.12. rl_check usage
1.12. pl_check usage
1.13. pl_drop usage
Chapter 1. Admin Guide
@ -85,6 +88,9 @@ Chapter 1. Admin Guide
Table of Contents
1. Overview
1.1. Algorithms
2. Dependencies
2.1. Kamailio Modules
@ -127,6 +133,8 @@ Chapter 1. Admin Guide
1. Overview
1.1. Algorithms
This module implements traffic limiting for SIP requests.
The module defines in an abstract mode the notion of 'pipe', which can
@ -138,8 +146,54 @@ Chapter 1. Admin Guide
Pipelimit started from ratelimit module, adding support for definition
of pipes limits in database and dynamic names. Complexity of keeping
everything in a module and make it dual mode functional resulted in a
new module which is focused on just traffic shaping policies. For
description of the algorithms see the README of ratelimit.
new module which is focused on just traffic shaping policies.
1.1. Algorithms
Algorithms are based from the ratelimit module, which describes the
algorithms in more detail. The algorithms are used by the pipelimit
module to determine if a message should be blocked.
Tail Drop Algorithm (TAILDROP)
This is a trivial algorithm that imposes some risks when used in
conjunction with long timer intervals. At the start of each interval an
internal counter is reset and incremented for each incoming message.
Once the counter hits the configured limit pl_check returns an error.
Random Early Detection Algorithm (RED)
The Random Early Detection Algorithm tries to circumvent the
synchronization problem imposed by the tail drop algorithm by measuring
the average load and adapting the drop rate dynamically. When running
with the RED algorithm (enabled by default) Kamailio will return errors
to the Kamailio routing engine every n'th packet trying to evenly
spread the measured load of the last timer interval onto the current
interval. As a negative side effect Kamailio might drop messages
although the limit might not be reached within the interval. Decrease
the timer interval if you encounter this.
Network Algorithm (NETWORK)
This algorithm relies on information provided by network interfaces.
The total amount of bytes waiting to be consumed on all the network
interfaces is retrieved once every timer_interval seconds. If the
returned amount exceeds the limit specified in the modparam, pl_check
returns an error.
Feedback Algorithm (FEEDBACK)
Using the PID Controller model (see Wikipedia page), the drop rate is
adjusted dynamically based on the load factor so that the load factor
always drifts towards the specified limit (or setpoint, in PID terms).
As reading the CPU load average is relatively expensive (opening
/proc/stat, parsing it, etc), this only happens once every
timer_interval seconds and consequently the FEEDBACK value is only at
these intervals recomputed. This in turn makes it difficult for the
drop rate to adjust quickly. Worst case scenarios are request rates
going up/down instantly by thousands - it takes up to 20 seconds for
the controller to adapt to the new request rate.
2. Dependencies
@ -298,7 +352,7 @@ kamcmd cfg.set_now_string pipelimit reply_reason "Limiting"
If algorithm and limit are provided, the function attempts to create a
new pipe of one with that name doesn't exit. If it exists, no changes
to algorithm and limit are done.
to algorithm and limit are done. Algorithm is case sensitive.
The pipe name can be provided via a pseudo variabile.
@ -311,13 +365,13 @@ kamcmd cfg.set_now_string pipelimit reply_reason "Limiting"
Meaning of the parameters is as follows:
* name - the string or pseudovariable with the pipe name.
* algorithm - the string or pseudovariable with the algorithm. The
values can be: taildrop, red, network or feedback - see readme of
values can be: TAILDROP, RED, NETWORK, or FEEDBACK - see readme of
ratelimit module for details on each algorithm.
* limit - the integer or pseudovariable with the limit value.
This function can be used from REQUEST_ROUTE.
Example 1.12. rl_check usage
Example 1.12. pl_check usage
...
# perform pipe match for current method
if (!pl_check("one")) {
@ -354,11 +408,20 @@ with unexpected retcode=$var(check_result)\n");
...
# perform pipe match for authenticated user
$var(limit) = 20;
if (!pl_check("$au", "traildrop", "$var(limit)")) {
if (!pl_check("$au", "TAILDROP", "$var(limit)")) {
pl_drop();
exit;
}
...
# perform pipe match for INVITE
if (is_method("INVITE")) {
$var(invlimit) = 10;
if (!pl_check("$si", "TAILDROP", "$var(invlimit)")) {
pl_drop();
exit;
}
}
...
4.2. pl_drop([ [min ], max ])

@ -166,7 +166,7 @@ static inline int get_event_flag(str* event)
return CONFERENCE_EVENT;
break;
case 14:
if (strncmp(event->s, "presence;winfo", 14) == 0)
if (strncmp(event->s, "presence.winfo", 14) == 0)
return PWINFO_EVENT;
break;
case 15:

@ -224,9 +224,9 @@ void reginfo_usrloc_cb(ucontact_t* c, int type, void* param) {
str content_type;
udomain_t * domain;
urecord_t * record;
ucontact_t* _c = NULL;
int res;
str uri = {NULL, 0};
str user = {NULL, 0};
char* at = NULL;
char id_buf[512];
@ -251,6 +251,9 @@ void reginfo_usrloc_cb(ucontact_t* c, int type, void* param) {
LM_ERR("Unknown Type %i\n", type);
return;
}
/* make a local copy of the AOR */
user.len = c->aor->len;
user.s = c->aor->s;
/* Get the UDomain for this account */
res = ul.get_udomain(c->domain->s, &domain);
@ -259,11 +262,10 @@ void reginfo_usrloc_cb(ucontact_t* c, int type, void* param) {
return;
}
/* Get the URecord for this ruid */
res = ul.get_urecord_by_ruid(domain, ul.get_aorhash(c->aor), &(c->ruid),
&record, &_c);
if (res < 0) {
LM_ERR("'%.*s (%.*s)' Not found in usrloc\n", c->aor->len, c->aor->s, c->domain->len, c->domain->s);
/* Get the URecord for this AOR */
res = ul.get_urecord(domain, &user, &record);
if (res > 0) {
LM_ERR("' %.*s (%.*s)' Not found in usrloc\n", c->aor->len, c->aor->s, c->domain->len, c->domain->s);
return;
}

@ -45,6 +45,7 @@ Daniel-Constantin Mierla
4.7. sbranch_set_ruri()
4.8. sbranch_append()
4.9. sbranch_reset()
4.10. pv_xavp_print()
5. MI Commands
@ -70,8 +71,9 @@ Daniel-Constantin Mierla
1.10. sbranch_set_ruri() usage
1.11. sbranch_append() usage
1.12. sbranch_append() usage
1.13. shv_set usage
1.14. shv_get usage
1.13. pv_xavp_print() usage
1.14. shv_set usage
1.15. shv_get usage
Chapter 1. Admin Guide
@ -100,6 +102,7 @@ Chapter 1. Admin Guide
4.7. sbranch_set_ruri()
4.8. sbranch_append()
4.9. sbranch_reset()
4.10. pv_xavp_print()
5. MI Commands
@ -203,6 +206,7 @@ modparam("pv","avp_aliases","email=s:email_addr;tmp=i:100")
4.7. sbranch_set_ruri()
4.8. sbranch_append()
4.9. sbranch_reset()
4.10. pv_xavp_print()
4.1. pv_isset(pvar)
@ -352,6 +356,17 @@ sbranch_append();
sbranch_reset();
...
4.10. pv_xavp_print()
Print all XAVPs to the syslog using INFO log level.
Function can be used from ANY_ROUTE.
Example 1.13. pv_xavp_print() usage
...
pv_xavp_print();
...
5. MI Commands
5.1. shv_set
@ -375,7 +390,7 @@ sbranch_reset();
_value_
_empty_line_
Example 1.13. shv_set usage
Example 1.14. shv_set usage
...
$ kamctl fifo shv_set debug int 0
...
@ -393,7 +408,7 @@ $ kamctl fifo shv_set debug int 0
_name_
_empty_line_
Example 1.14. shv_get usage
Example 1.15. shv_get usage
...
$ kamctl fifo shv_get debug
$ kamctl fifo shv_get

@ -2808,7 +2808,7 @@ int pv_parse_hdr_name(pv_spec_p sp, str *in)
s.s = p;
s.len = in->len+1;
if (parse_hname2(s.s, s.s + ((s.len<4)?4:s.len), &hdr)==0)
if (parse_hname2_short(s.s, s.s + s.len, &hdr)==0)
{
LM_ERR("error parsing header name [%.*s]\n", s.len, s.s);
goto error;

@ -891,15 +891,16 @@ lookup_branches("location");
4.4. registered(domain [, uri [, match_option [, match_action]]])
The function returns true if the AOR in the Request-URI is registered,
false otherwise. The function does not modify the message being
process, it neither rewrites the Request-URI if a contact is found nor
append branches.
The function returns true if the AOR in the URI is registered, false
otherwise. The function does not modify the message being process, it
neither rewrites the Request-URI if a contact is found nor append
branches. If uri parameter is not provided, then it considered to be
the Request-URI for SIP requests and To-URI for SIP replies.
Meaning of the parameters is as follows:
* domain - Name of table that should be used for the lookup.
* uri (optional) - SIP URI to do be used instead of R-URI. It can be
a dynamic string with pseudo-variables.
* uri (optional) - SIP URI to do be used instead of Request/To-URI.
It can be a dynamic string with pseudo-variables.
* match_option (optional) - flag parameter to restrict contact
search. use reg_xavp_cfg to set the values to compare to.
flag values is as follows:
@ -911,7 +912,7 @@ lookup_branches("location");
flag values is as follows:
+ 1 - set xavp_rcd with value from matched contact
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
This function can be used from ANY_ROUTE.
Example 1.31. registered usage
...

@ -1110,10 +1110,12 @@ lookup_branches("location");
<function moreinfo="none">registered(domain [, uri [, match_option [, match_action]]])</function>
</title>
<para>
The function returns true if the AOR in the Request-URI is
The function returns true if the AOR in the URI is
registered, false otherwise. The function does not modify the
message being process, it neither rewrites the Request-URI if a
contact is found nor append branches.
contact is found nor append branches. If uri parameter is not
provided, then it considered to be the Request-URI for SIP requests
and To-URI for SIP replies.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
@ -1126,7 +1128,7 @@ lookup_branches("location");
<listitem>
<para>
<emphasis>uri</emphasis> (optional) - SIP URI to do be used instead
of R-URI. It can be a dynamic string with pseudo-variables.
of Request/To-URI. It can be a dynamic string with pseudo-variables.
</para>
</listitem>
<listitem>
@ -1160,7 +1162,7 @@ lookup_branches("location");
</listitem>
</itemizedlist>
<para>
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
This function can be used from ANY_ROUTE.
</para>
<example>
<title><function>registered</function> usage</title>

@ -36,6 +36,7 @@
#include "../../action.h"
#include "../../mod_fix.h"
#include "../../parser/parse_rr.h"
#include "../../parser/parse_to.h"
#include "../../forward.h"
#include "../usrloc/usrloc.h"
#include "common.h"
@ -642,8 +643,16 @@ int registered4(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag, in
{
uri = *_uri;
} else {
if (_m->new_uri.s) uri = _m->new_uri;
else uri = _m->first_line.u.request.uri;
if(IS_SIP_REPLY(_m)) {
if (parse_to_header(_m) < 0) {
LM_ERR("failed to prepare the message\n");
return -1;
}
uri = get_to(_m)->uri;
} else {
if (_m->new_uri.s) uri = _m->new_uri;
else uri = _m->first_line.u.request.uri;
}
}
if (extract_aor(&uri, &aor, NULL) < 0) {

@ -41,6 +41,7 @@
#include "../../error.h"
#include "../../socket_info.h"
#include "../../pvar.h"
#include "../../dset.h"
#include "../../modules/usrloc/usrloc.h"
#include "../../lib/kcore/statistics.h"
#include "../../lib/srutils/sruid.h"
@ -163,13 +164,13 @@ static cmd_export_t cmds[] = {
{"lookup_to_dset", (cmd_function)w_lookup_to_dset, 1, domain_uri_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
{"registered", (cmd_function)w_registered, 1, domain_uri_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
ANY_ROUTE },
{"registered", (cmd_function)w_registered, 2, domain_uri_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
ANY_ROUTE },
{"registered", (cmd_function)w_registered3, 3, registered_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
ANY_ROUTE },
{"registered", (cmd_function)w_registered4, 4, registered_fixup, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
ANY_ROUTE },
{"add_sock_hdr", (cmd_function)add_sock_hdr, 1, fixup_str_null, 0,
REQUEST_ROUTE },
{"unregister", (cmd_function)w_unregister, 2, unreg_fixup, 0,
@ -384,6 +385,8 @@ static int mod_init(void)
sock_flag = (sock_flag!=-1)?(1<<sock_flag):0;
tcp_persistent_flag = (tcp_persistent_flag!=-1)?(1<<tcp_persistent_flag):0;
set_aor_case_sensitive(cfg_get(registrar, registrar_cfg, case_sensitive));
return 0;
}

@ -307,6 +307,20 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
}
ci.server_id = server_id;
if(_m->contact) {
_c = (((contact_body_t*)_m->contact->parsed)->contacts);
if(_c->instance!=NULL && _c->instance->body.len>0) {
ci.instance = _c->instance->body;
LM_DBG("set instance[%.*s]\n", ci.instance.len, ci.instance.s);
}
if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0)
{
LM_ERR("invalid reg-id value\n");
goto error;
}
}
}
allow_parsed = 0; /* not parsed yet */
received_found = 0; /* not found yet */

@ -781,9 +781,9 @@ int rls_handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_doma
}
}
if (dbmode != RLS_DB_ONLY)
if (get_to(msg)->tag_value.s==NULL || get_to(msg)->tag_value.len==0)
{
/* sending notify with full state */
/* initial subscriber - sending notify with full state */
if(send_full_notify(&subs, service_node, &subs.pres_uri, hash_code)<0)
{
LM_ERR("failed sending full state notify\n");

@ -757,7 +757,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
int status = RR_DRIVEN;
str uri;
struct socket_info *si;
int uri_is_myself, next_is_strict;
int uri_is_myself;
int use_ob = 0;
hdr = _m->route;
@ -768,11 +768,11 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
routed_msg_id = 0;
if (parse_uri(uri.s, uri.len, &puri) < 0) {
LM_ERR("failed to parse the first route URI\n");
LM_ERR("failed to parse the first route URI (%.*s)\n",
uri.len, ZSW(uri.s));
return RR_ERROR;
}
next_is_strict = is_strict(&puri.params);
routed_params = puri.params;
uri_is_myself = is_myself(&puri);
@ -815,7 +815,8 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
/* double route may occure due different IP and port, so force as
* send interface the one advertise in second Route */
if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) {
LM_ERR("failed to parse the double route URI\n");
LM_ERR("failed to parse the double route URI (%.*s)\n",
rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s));
return RR_ERROR;
}
@ -852,7 +853,8 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
uri = rt->nameaddr.uri;
if (parse_uri(uri.s, uri.len, &puri) < 0) {
LM_ERR("failed to parse the first route URI\n");
LM_ERR("failed to parse the next route URI (%.*s)\n",
uri.len, ZSW(uri.s));
return RR_ERROR;
}
} else {
@ -867,7 +869,7 @@ static inline int after_loose(struct sip_msg* _m, int preloaded)
}
LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s));
if (next_is_strict) {
if (is_strict(&puri.params)) {
LM_DBG("Next URI is a strict router\n");
if (handle_sr(_m, hdr, rt) < 0) {
LM_ERR("failed to handle strict router\n");

@ -101,7 +101,7 @@ Richard Fuchs
1.6. Set extra_id_pv parameter
1.7. Set setid_avp parameter
1.8. Set force_send_interface parameter
1.9. Set write_sdp_avp parameter
1.9. Set write_sdp_pv parameter
1.10. Set rtp_inst_pvar parameter
1.11. set_rtpengine_set usage
1.12. rtpengine_offer usage
@ -350,9 +350,11 @@ modparam("rtpengine", "force_send_interface", "10.3.7.123")
There is no default value.
Example 1.9. Set write_sdp_avp parameter
Example 1.9. Set write_sdp_pv parameter
...
modparam("rtpengine", "write_sdp_avp", "$avp(sdp)")
modparam("rtpengine", "write_sdp_pv", "$avp(sdp)")
... or
modparam("rtpengine", "write_sdp_pv", "$pv(sdp)")
...
4.10. rtp_inst_pvar (string)

@ -298,10 +298,12 @@ modparam("rtpengine", "force_send_interface", "2001:8d8:1ff:10c0:9a90:96ff:fea8:
There is no default value.
</para>
<example>
<title>Set <varname>write_sdp_avp</varname> parameter</title>
<title>Set <varname>write_sdp_pv</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("rtpengine", "write_sdp_avp", "$avp(sdp)")
modparam("rtpengine", "write_sdp_pv", "$avp(sdp)")
... or
modparam("rtpengine", "write_sdp_pv", "$pv(sdp)")
...
</programlisting>
</example>

@ -652,19 +652,18 @@ int check_proxy_require(struct sip_msg* _msg) {
int u_len;
#ifdef EXTRA_DEBUG
DBG("check_proxy_require entered\n");
LM_DBG("checking proxy require\n");
#endif
if (parse_headers(_msg, HDR_PROXYREQUIRE_F, 0) != 0) {
LOG(L_WARN, "sanity_check(): check_proxy_require():"
" failed to parse proxy require header\n");
LM_WARN("failed to parse proxy require header\n");
return SANITY_CHECK_FAILED;
}
if (_msg->proxy_require != NULL) {
dump_hdr_field(_msg->proxy_require);
//dump_hdr_field(_msg->proxy_require);
if (_msg->proxy_require->parsed == NULL &&
parse_proxyrequire(_msg->proxy_require) < 0) {
LOG(L_WARN, "sanity_check(): check_proxy_require(): parse_proxy_require failed\n");
LM_WARN("parse_proxy_require failed\n");
return SANITY_CHECK_FAILED;
}
r_pr = _msg->proxy_require->parsed;
@ -672,7 +671,7 @@ int check_proxy_require(struct sip_msg* _msg) {
l_pr = proxyrequire_list;
while (l_pr != NULL) {
#ifdef EXTRA_DEBUG
DBG("check_proxy_require(): comparing r='%.*s' l='%.*s'\n",
LM_DBG("comparing r='%.*s' l='%.*s'\n",
r_pr->string.len, r_pr->string.s, l_pr->string.len,
l_pr->string.s);
#endif
@ -685,14 +684,12 @@ int check_proxy_require(struct sip_msg* _msg) {
l_pr = l_pr->next;
}
if (l_pr == NULL) {
DBG("sanit_check(): check_proxy_require():"
" request contains unsupported extension: %.*s\n",
LM_DBG("request contains unsupported extension: %.*s\n",
r_pr->string.len, r_pr->string.s);
u_len = UNSUPPORTED_HEADER_LEN + 2 + r_pr->string.len;
u = pkg_malloc(u_len);
if (u == NULL) {
LOG(L_ERR, "sanity_check(): check_proxy_require():"
" failed to allocate memory for"
LM_ERR("failed to allocate memory for"
" Unsupported header\n");
}
else {
@ -706,12 +703,11 @@ int check_proxy_require(struct sip_msg* _msg) {
if (_msg->REQ_METHOD != METHOD_ACK) {
if (sanity_reply(_msg, 420, "Bad Extension") < 0) {
LOG(L_WARN, "sanity_check(): check_proxy_require():"
" failed to send 420 via sl reply\n");
LM_WARN("failed to send 420 via sl reply\n");
}
}
#ifdef EXTRA_DEBUG
DBG("check_proxy_require failed\n");
LM_DBG("checking proxy require failed\n");
#endif
if (u) pkg_free(u);
return SANITY_CHECK_FAILED;
@ -721,7 +717,7 @@ int check_proxy_require(struct sip_msg* _msg) {
}
}
#ifdef EXTRA_DEBUG
DBG("check_proxy_require passed\n");
LM_DBG("checking proxy require passed\n");
#endif
if (_msg->proxy_require->parsed) {
/* TODO we have to free it here, because it is not automatically
@ -732,7 +728,7 @@ int check_proxy_require(struct sip_msg* _msg) {
}
#ifdef EXTRA_DEBUG
else {
DBG("check_proxy_require(): no proxy-require header found\n");
LM_DBG("no proxy-require header found\n");
}
#endif

@ -235,7 +235,7 @@ modparam("sctp", "sctp_send_retries", 1)
better performance, but it will also disable some other features that
depend on it (e.g. sctp_assoc_reuse).
Can be changed at runtime (sercmd sctp assoc_tracking 0), but changes
Can be changed at runtime (kamcmd sctp assoc_tracking 0), but changes
will be allowed only if all the other features that depend on it are
turned off (for example it can be turned off only if first
sctp_assoc_reuse was turned off).

@ -194,7 +194,7 @@ modparam("sctp", "sctp_send_retries", 1)
features that depend on it (e.g. sctp_assoc_reuse).
</para>
<para>
Can be changed at runtime (sercmd sctp assoc_tracking 0), but changes
Can be changed at runtime (&sercmd; sctp assoc_tracking 0), but changes
will be allowed only if all the other features that depend on it are
turned off (for example it can be turned off only if first
sctp_assoc_reuse was turned off).

@ -535,6 +535,11 @@ static int sip_trace_prepare(sip_msg_t *msg)
goto error;
}
if(parse_to_header(msg)==-1 || msg->to==NULL || get_to(msg)==NULL) {
LM_ERR("cannot parse To header\n");
goto error;
}
if(parse_headers(msg, HDR_CALLID_F, 0)!=0 || msg->callid==NULL
|| msg->callid->body.s==NULL) {
LM_ERR("cannot parse call-id\n");
@ -757,6 +762,11 @@ static int sip_trace_store(struct _siptrace_data *sto, struct dest_info *dst)
static int sip_trace_store_db(struct _siptrace_data *sto)
{
if(db_con==NULL) {
LM_DBG("database connection not initialized\n");
return -1;
}
if(trace_to_database_flag==NULL || *trace_to_database_flag==0)
goto done;

@ -104,7 +104,6 @@ int sql_parse_index(str *in, gparam_t *gp)
if (gp->v.pvs == NULL)
{
LM_ERR("no pkg memory left for pv_spec_t\n");
pkg_free(gp);
return -1;
}
@ -112,7 +111,6 @@ int sql_parse_index(str *in, gparam_t *gp)
{
LM_ERR("invalid PV identifier\n");
pkg_free(gp->v.pvs);
pkg_free(gp);
return -1;
}
} else {
@ -257,7 +255,9 @@ int pv_parse_dbr_name(pv_spec_p sp, str *in)
if(p>in->s+in->len || *p=='\0' || *p!=']')
goto error_index;
} else {
LM_ERR("unknow key [%.*s]\n", pvs.len, pvs.s);
LM_ERR("unknown key [%.*s]\n", pvs.len, pvs.s);
if(spv!=NULL)
pkg_free(spv);
return -1;
}
sp->pvp.pvn.u.dname = (void*)spv;

@ -2226,8 +2226,7 @@ static int hname_fixup(void** param, int param_no)
gp->v.str.s[gp->v.str.len] = ':';
gp->v.str.len++;
if (parse_hname2(gp->v.str.s, gp->v.str.s
+ ((gp->v.str.len<4)?4:gp->v.str.len), &hdr)==0)
if (parse_hname2_short(gp->v.str.s, gp->v.str.s + gp->v.str.len, &hdr)==0)
{
LM_ERR("error parsing header name\n");
pkg_free(gp);

@ -124,7 +124,7 @@ int tr_txt_eval_re(struct sip_msg *msg, tr_param_t *tp, int subtype,
return 0;
error:
if (tp->type == TR_PARAM_SPEC) {
if (tp->type == TR_PARAM_SPEC && se!=NULL) {
subst_expr_free(se);
}
return -1;

@ -544,7 +544,7 @@ static int fixup_hname_param(char *hname, struct hname_data** h) {
(*h)->hname.len = hname - (*h)->hname.s;
savec = *hname;
*hname = ':';
parse_hname2((*h)->hname.s, (*h)->hname.s+(*h)->hname.len+3, &hdr);
parse_hname2_short((*h)->hname.s, (*h)->hname.s+(*h)->hname.len+1, &hdr);
*hname = savec;
if (hdr.type == HDR_ERROR_T) goto err;

@ -1317,7 +1317,7 @@ modparam("tm", "via1_matching", 1)
Default value is 0 (off).
Can be set at runtime, e.g.:
$ sercmd cfg.set_now_int tm callid_matching 0
$ kamcmd cfg.set_now_int tm callid_matching 0
Example 1.33. Set callid_matching parameter
...
@ -1634,7 +1634,7 @@ modparam("tm|usrloc", "xavp_contact", "ulattrs")
5.50. t_use_uac_headers()
5.51. t_is_retr_async_reply()
5.1. t_relay([host, port])
5.1. t_relay([host, port])
Relay a message statefully either to the destination indicated in the
current URI (if called without any parameters) or to the specified host
@ -1662,7 +1662,7 @@ if (!t_relay())
};
...
5.2. t_relay_to_udp([ip, port])
5.2. t_relay_to_udp([ip, port])
Relay a message statefully using a fixed protocol either to the
specified fixed destination or to a destination derived from the
@ -1688,19 +1688,19 @@ else
t_relay_to_tcp(); # relay to msg. uri, but over tcp
...
5.3. t_relay_to_tcp([ip, port])
5.3. t_relay_to_tcp([ip, port])
See function t_relay_to_udp([ip, port]).
5.4. t_relay_to_tls([ip, port])
5.4. t_relay_to_tls([ip, port])
See function t_relay_to_udp([ip, port]).
5.5. t_relay_to_sctp([ip, port])
5.5. t_relay_to_sctp([ip, port])
See function t_relay_to_udp([ip, port]).
5.6. t_on_failure(failure_route)
5.6. t_on_failure(failure_route)
Sets failure routing block, to which control is passed after a
transaction completed with a negative result but before sending a final
@ -1737,14 +1737,14 @@ failure_route[1] {
See test/onr.cfg for a more complex example of combination of serial
with parallel forking.
5.7. t_on_branch_failure(branch_failure_route)
5.7. t_on_branch_failure(branch_failure_route)
Sets the branch_failure routing block, to which control is passed on
each negative response to a transaction. This route is run before
deciding if the transaction is complete. In the referred block, you can
start a new branch which is required for failover of multiple outbound
flows (RFC 5626). Note that the set of commands which are usable within
a branch_failure route is limited to a subset of the failure_route
a branch_failure route is limited to a subset of the failure_rotue
commands including logging, rewriting URI and initiating new branches.
Any other commands may generate errors or result in unpredictable
behavior. Note that whenever failure_route is entered, uri is reset to
@ -1770,7 +1770,7 @@ event_route[tm:branch-failure:myroute] {
}
...
5.8. t_on_reply(onreply_route)
5.8. t_on_reply(onreply_route)
Sets the reply routing block, to which control is passed when a reply
for the current transaction is received. Note that the set of commands
@ -1800,7 +1800,7 @@ es');
}
}
5.9. t_on_branch(branch_route)
5.9. t_on_branch(branch_route)
Sets the branch routing block, to which control is passed after forking
(when a new branch is created). For now branch routes are intended only
@ -1824,7 +1824,7 @@ branch_route[1] {
}
}
5.10. t_newtran()
5.10. t_newtran()
Creates a new transaction, returns a negative value on error. This is
the only way a script can add a new transaction in an atomic way.
@ -1840,7 +1840,7 @@ if (t_newtran()) {
See test/uas.cfg for more examples.
5.11. t_reply(code, reason_phrase)
5.11. t_reply(code, reason_phrase)
Sends a stateful reply after a transaction has been established. See
t_newtran for usage.
@ -1865,7 +1865,7 @@ if (t_newtran()) {
t_reply("404", "Not found");
...
5.12. t_lookup_request()
5.12. t_lookup_request()
Checks if a transaction exists. Returns a positive value if so,
negative otherwise. Most likely you will not want to use it, as a
@ -1880,7 +1880,7 @@ if (t_lookup_request()) {
};
...
5.13. t_retransmit_reply()
5.13. t_retransmit_reply()
Retransmits a reply sent previously by UAS transaction.
@ -1889,7 +1889,7 @@ if (t_lookup_request()) {
t_retransmit_reply();
...
5.14. t_release()
5.14. t_release()
Remove transaction from memory (it will be first put on a wait timer to
absorb delayed messages).
@ -1899,7 +1899,7 @@ t_retransmit_reply();
t_release();
...
5.15. t_forward_nonack([ip, port])
5.15. t_forward_nonack([ip, port])
Mainly for internal usage -- forward a non-ACK request statefully.
Variants of this functions can enforce a specific transport protocol.
@ -1913,23 +1913,23 @@ t_release();
t_forward_nonack("1.2.3.4", "5060");
...
5.16. t_forward_nonack_udp(ip, port)
5.16. t_forward_nonack_udp(ip, port)
See function t_forward_nonack([ip, port]).
5.17. t_forward_nonack_tcp(ip, port)
5.17. t_forward_nonack_tcp(ip, port)
See function t_forward_nonack([ip, port]).
5.18. t_forward_nonack_tls(ip, port)
5.18. t_forward_nonack_tls(ip, port)
See function t_forward_nonack([ip, port]).
5.19. t_forward_nonack_sctp(ip, port)
5.19. t_forward_nonack_sctp(ip, port)
See function t_forward_nonack([ip, port]).
5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
5.20. t_set_fr(fr_inv_timeout [, fr_timeout])
Sets the fr_inv_timeout and optionally fr_timeout for the current
transaction or for transactions created during the same script
@ -1963,7 +1963,7 @@ branch_route[1] {
}
}
5.21. t_reset_fr()
5.21. t_reset_fr()
Resets the fr_inv_timer and fr_timer for the current transaction to the
default values (set using the tm module parameters fr_inv_timer and
@ -1982,7 +1982,7 @@ route {
...
}
5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
5.22. t_set_max_lifetime(inv_lifetime, noninv_lifetime)
Sets the maximum lifetime for the current INVITE or non-INVITE
transaction, or for transactions created during the same script
@ -2011,7 +2011,7 @@ route {
# INVITE and to 15s if not
}
5.23. t_reset_max_lifetime()
5.23. t_reset_max_lifetime()
Resets the the maximum lifetime for the current INVITE or non-INVITE
transaction to the default value (set using the tm module parameter
@ -2030,7 +2030,7 @@ route {
...
}
5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
5.24. t_set_retr(retr_t1_interval, retr_t2_interval)
Sets the retr_t1_interval and retr_t2_interval for the current
transaction or for transactions created during the same script
@ -2076,7 +2076,7 @@ branch_route[1] {
}
}
5.25. t_reset_retr()
5.25. t_reset_retr()
Resets the retr_timer1 and retr_timer2 for the current transaction to
the default values (set using the tm module parameters retr_timer1 and
@ -2095,7 +2095,7 @@ route {
...
}
5.26. t_set_auto_inv_100(0|1)
5.26. t_set_auto_inv_100(0|1)
Switch automatically sending 100 replies to INVITEs on/off on a per
transaction basis. It overrides the auto_inv_100 value for the current
@ -2112,7 +2112,7 @@ route {
...
}
5.27. t_branch_timeout()
5.27. t_branch_timeout()
Returns true if the failure route is executed for a branch that did
timeout. It can be used from failure_route and branch-failure event
@ -2127,7 +2127,7 @@ failure_route[0]{
}
}
5.28. t_branch_replied()
5.28. t_branch_replied()
Returns true if the failure route is executed for a branch that did
receive at least one reply in the past (the "current" reply is not
@ -2146,7 +2146,7 @@ failure_route[0]{
}
}
5.29. t_any_timeout()
5.29. t_any_timeout()
Returns true if at least one of the current transactions branches did
timeout.
@ -2162,7 +2162,7 @@ failure_route[0]{
}
}
5.30. t_any_replied()
5.30. t_any_replied()
Returns true if at least one of the current transactions branches did
receive some reply in the past. If called from a failure or onreply
@ -2177,7 +2177,7 @@ onreply_route[0]{
}
}
5.31. t_grep_status("code")
5.31. t_grep_status("code")
Returns true if "code" is the final reply received (or locally
generated) in at least one of the current transactions branches.
@ -2191,7 +2191,7 @@ onreply_route[0]{
}
}
5.32. t_is_canceled()
5.32. t_is_canceled()
Returns true if the current transaction was canceled.
@ -2204,7 +2204,7 @@ failure_route[0]{
}
}
5.33. t_is_expired()
5.33. t_is_expired()
Returns true if the current transaction has already been expired, i.e.
the max_inv_lifetime/max_noninv_lifetime interval has already elapsed.
@ -2218,7 +2218,7 @@ failure_route[0]{
}
}
5.34. t_relay_cancel()
5.34. t_relay_cancel()
Forwards the CANCEL if the corresponding INVITE transaction exists. The
function is supposed to be used at the very beginning of the script,
@ -2243,7 +2243,7 @@ if (method == CANCEL) {
# do the same as for INVITEs
}
5.35. t_lookup_cancel([1])
5.35. t_lookup_cancel([1])
Returns true if the corresponding INVITE transaction exists for a
CANCEL request. The function can be called at the beginning of the
@ -2275,7 +2275,7 @@ if (method == CANCEL) {
# do the same as for INVITEs
}
5.36. t_drop_replies([mode])
5.36. t_drop_replies([mode])
Drops all the previously received replies in failure_route block to
make sure that none of them is picked up again.
@ -2303,7 +2303,7 @@ failure_route[0]{
}
}
5.37. t_save_lumps()
5.37. t_save_lumps()
Forces the modifications of the processed SIP message to be saved in
shared memory before t_relay() is called. The new branches which are
@ -2343,7 +2343,7 @@ failure_route[1] {
t_relay();
}
5.38. t_load_contacts()
5.38. t_load_contacts()
This is the first of the three functions that can be used to implement
serial/parallel forking based on q and +sip.instance values of
@ -2385,7 +2385,7 @@ if (!t_load_contacts()) {
};
...
5.39. t_next_contacts()
5.39. t_next_contacts()
Function t_next_contacts() is the second of the three functions that
can be used to implement serial/parallel forking based on the q value
@ -2437,7 +2437,7 @@ if (!t_next_contacts()) {
};
...
5.40. t_next_contact_flow()
5.40. t_next_contact_flow()
Function t_next_contact_flow() is the last of the three functions that
can be used to implement serial/parallel forking based on the q value
@ -2467,7 +2467,7 @@ event_route[tm:branch-failure:outbound]
}
...
5.41. t_check_status(re)
5.41. t_check_status(re)
Returns true if the regular expresion "re" match the reply code of the
response message as follows:
@ -2485,7 +2485,7 @@ if (t_check_status("(487)|(408)")) {
}
...
5.42. t_check_trans()
5.42. t_check_trans()
t_check_trans() can be used to quickly check if a message belongs or is
related to a transaction. It behaves differently for different types of
@ -2537,7 +2537,7 @@ if ( method == "CANCEL" && !t_check_trans())
sl_reply("403", "cancel out of the blue forbidden");
# note: in this example t_check_trans() can be replaced by t_lookup_cancel()
5.43. t_set_disable_6xx(0|1)
5.43. t_set_disable_6xx(0|1)
Turn off/on 6xx replies special rfc conformant handling on a per
transaction basis. If turned off (t_set_disable_6xx("1")) 6XXs will be
@ -2556,7 +2556,7 @@ route {
...
}
5.44. t_set_disable_failover(0|1)
5.44. t_set_disable_failover(0|1)
Turn off/on dns failover on a per transaction basis.
@ -2571,7 +2571,7 @@ route {
...
}
5.45. t_set_disable_internal_reply(0|1)
5.45. t_set_disable_internal_reply(0|1)
Turn off/on sending internally a SIP reply in case of relay errors.
@ -2583,7 +2583,7 @@ if(!t_relay()) {
}
...
5.46. t_replicate([params])
5.46. t_replicate([params])
Replicate the SIP request to a specific address.
@ -2619,7 +2619,7 @@ t_replicate("sip:$var(h);transport=tls");
t_replicate_to_udp("1.2.3.4", "5060");
...
5.47. t_relay_to(proxy, flags)
5.47. t_relay_to(proxy, flags)
Forward the SIP request to a specific address, controlling internal
behavior via flags.
@ -2652,7 +2652,7 @@ t_relay_to("tls:1.2.3.4");
t_relay_to("0x01");
...
5.48. t_set_no_e2e_cancel_reason(0|1)
5.48. t_set_no_e2e_cancel_reason(0|1)
Enables/disables reason header (RFC 3326) copying from the triggering
received CANCEL to the generated hop-by-hop CANCEL. 0 enables and 1
@ -2661,6 +2661,9 @@ t_relay_to("0x01");
It overrides the e2e_cancel_reason setting (module parameter) for the
current transaction.
Note: the function has to be used when processing the INVITE (not when
processing the CANCEL).
See also: e2e_cancel_reason.
Example 1.87. t_set_no_e2e_cancel_reason usage
@ -2673,7 +2676,7 @@ opying
...
}
5.49. t_is_set(target)
5.49. t_is_set(target)
Return true if the attribute specified by 'target' is set for
transaction.
@ -2692,7 +2695,7 @@ if(!t_is_set("failure_route"))
LM_DBG("no failure route will be executed for current transaction\n");
...
5.50. t_use_uac_headers()
5.50. t_use_uac_headers()
Set internal flags to tell tm to use UAC side for building headers for
local generated requests (ACK, CANCEL) - useful when changing From/To
@ -2705,7 +2708,7 @@ if(!t_is_set("failure_route"))
t_use_uac_headers();
...
5.51. t_is_retr_async_reply()
5.51. t_is_retr_async_reply()
Check to see if the reply is a retransmitted reply on a transaction
that is currently suspended asynchronously (suspended during reply
@ -2808,7 +2811,7 @@ end of body
6.2. Functions
6.2.1. register_tmcb(cb_type, cb_func)
6.2.1. register_tmcb(cb_type, cb_func)
For programmatic use only--register a function to be called back on an
event. See t_hooks.h for more details.
@ -2817,7 +2820,7 @@ end of body
* cb_type - Callback type.
* cb_func - Callback function.
6.2.2. load_tm(*import_structure)
6.2.2. load_tm(*import_structure)
For programmatic use only--import exported TM functions. See the acc
module for an example of use.
@ -2825,7 +2828,7 @@ end of body
Meaning of the parameters is as follows:
* import_structure - Pointer to the import structure.
6.2.3. int t_suspend(struct sip_msg *msg, unsigned int *hash_index, unsigned
6.2.3. int t_suspend(struct sip_msg *msg, unsigned int *hash_index, unsigned
int *label)
For programmatic use only. This function together with t_continue() can
@ -2863,7 +2866,7 @@ int *label)
t_suspend() should return 0 to make sure that the script processing
does not continue.
6.2.4. int t_continue(unsigned int hash_index, unsigned int label, struct
6.2.4. int t_continue(unsigned int hash_index, unsigned int label, struct
action *route)
For programmatic use only. This function is the pair of t_suspend(),
@ -2879,7 +2882,7 @@ action *route)
Return value: 0 - success, <0 - error.
6.2.5. int t_cancel_suspend(unsigned int hash_index, unsigned int label)
6.2.5. int t_cancel_suspend(unsigned int hash_index, unsigned int label)
For programmatic use only. This function is for revoking t_suspend()
from the same process as it was executed before. t_cancel_suspend() can
@ -2899,7 +2902,7 @@ action *route)
7.1. event_route[tm:branch-failure]
7.1. event_route[tm:branch-failure]
7.1. event_route[tm:branch-failure]
Named branch failure routes can be defined to run when when a failure
response is received. This allows handling failures on individual

@ -1664,6 +1664,10 @@ t_relay_to("0x01");
It overrides the <varname>e2e_cancel_reason</varname> setting (module
parameter) for the current transaction.
</para>
<para>
Note: the function has to be used when processing the INVITE
(not when processing the CANCEL).
</para>
<para>
See also: <varname>e2e_cancel_reason</varname>.
</para>

@ -1003,7 +1003,7 @@ modparam("tm", "via1_matching", 1)
<para>
Can be set at runtime, e.g.:
<programlisting>
$ sercmd cfg.set_now_int tm callid_matching 0
$ &sercmd; cfg.set_now_int tm callid_matching 0
</programlisting>
</para>
<example>

@ -106,17 +106,14 @@ int t_append_branches(void) {
set_branch_route(t->on_branch_delayed);
}
outgoings = t->nr_of_outgoings;
/* not really sure that the following is needed */
init_branch_iterator();
set_branch_iterator(nr_branches-1);
found = 0;
while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri, &path,
&bflags, &si, &ruid, &instance, &location_ua))) {
LM_DBG("Current uri %.*s\n",current_uri.len, current_uri.s);
for (i=0; i<nr_branches; i++) {
found = 0;
for (i=0; i<outgoings; i++) {
if (t->uac[i].ruid.len == ruid.len
&& !memcmp(t->uac[i].ruid.s, ruid.s, ruid.len)) {
LM_DBG("branch already added [%.*s]\n", ruid.len, ruid.s);
@ -131,8 +128,10 @@ int t_append_branches(void) {
new_branch=add_uac( t, orig_msg, &current_uri,
(dst_uri.len) ? (&dst_uri) : &current_uri,
&path, 0, si, orig_msg->fwd_send_flags,
orig_msg->rcv.proto, (dst_uri.len)?-1:UAC_SKIP_BR_DST_F, &instance,
PROTO_NONE, (dst_uri.len)?-1:UAC_SKIP_BR_DST_F, &instance,
&ruid, &location_ua);
LM_DBG("added branch [%.*s] with ruid [%.*s]\n", current_uri.len, current_uri.s, ruid.len, ruid.s);
/* test if cancel was received meanwhile */
if (t->flags & T_CANCELED) goto canceled;

@ -982,6 +982,8 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
* set next failure route, failure_route will not be reentered
* on failure */
t->on_failure=0;
/* if continuing on timeout of a suspended transaction, reset the flag */
t->flags &= ~T_ASYNC_SUSPENDED;
if (exec_pre_script_cb(&faked_req, FAILURE_CB_TYPE)>0) {
/* run a failure_route action if some was marked */
if (run_top_route(failure_rt.rlist[on_failure], &faked_req, 0)<0)
@ -1729,6 +1731,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
str* to_tag;
str reason;
struct tmcb_params onsend_params;
struct ip_addr ip;
/* keep compiler warnings about use of uninit vars silent */
res_len=0;
@ -1737,7 +1740,6 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
relayed_code=0;
totag_retr=0;
/* remember, what was sent upstream to know whether we are
* forwarding a first final reply or not */
@ -1921,26 +1923,41 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
if (reply_status == RPS_COMPLETED) {
start_final_repl_retr(t);
}
if (likely(uas_rb->dst.send_sock &&
SEND_PR_BUFFER( uas_rb, buf, res_len ) >= 0)){
if (unlikely(!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT))){
LOCK_REPLIES( t );
run_trans_callbacks_with_buf( TMCB_RESPONSE_OUT, uas_rb, t->uas.request,
relayed_msg, relayed_code);
UNLOCK_REPLIES( t );
if (likely(uas_rb->dst.send_sock)) {
if (onsend_route_enabled(SIP_REPLY) && p_msg && (p_msg != FAKED_REPLY)) {
if (run_onsend(p_msg, &uas_rb->dst, buf, res_len)==0){
su2ip_addr(&ip, &(uas_rb->dst.to));
LOG(L_ERR, "forward_reply: reply to %s:%d(%d) dropped"
" (onsend_route)\n", ip_addr2a(&ip),
su_getport(&(uas_rb->dst.to)), uas_rb->dst.proto);
/* workaround for drop - reset send_sock to skip sending out */
uas_rb->dst.send_sock = 0;
}
}
if (unlikely(has_tran_tmcbs(t, TMCB_RESPONSE_SENT))){
INIT_TMCB_ONSEND_PARAMS(onsend_params, t->uas.request,
relayed_msg, uas_rb, &uas_rb->dst, buf,
res_len,
(relayed_msg==FAKED_REPLY)?TMCB_LOCAL_F:0,
uas_rb->branch, relayed_code);
LOCK_REPLIES( t );
run_trans_callbacks_off_params(TMCB_RESPONSE_SENT, t, &onsend_params);
UNLOCK_REPLIES( t );
}
if (likely(uas_rb->dst.send_sock)) {
if (SEND_PR_BUFFER( uas_rb, buf, res_len ) >= 0){
if (unlikely(!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT))){
LOCK_REPLIES( t );
run_trans_callbacks_with_buf( TMCB_RESPONSE_OUT, uas_rb, t->uas.request,
relayed_msg, relayed_code);
UNLOCK_REPLIES( t );
}
if (unlikely(has_tran_tmcbs(t, TMCB_RESPONSE_SENT))){
INIT_TMCB_ONSEND_PARAMS(onsend_params, t->uas.request,
relayed_msg, uas_rb, &uas_rb->dst, buf,
res_len,
(relayed_msg==FAKED_REPLY)?TMCB_LOCAL_F:0,
uas_rb->branch, relayed_code);
LOCK_REPLIES( t );
run_trans_callbacks_off_params(TMCB_RESPONSE_SENT, t, &onsend_params);
UNLOCK_REPLIES( t );
}
}
} else if (unlikely(uas_rb->dst.send_sock == 0))
ERR("no resolved dst to send reply to\n");
} else {
LM_NOTICE("dst no longer set - skiped sending the reply out\n");
}
/* Call put_on_wait() only if we really send out
* the reply. It can happen that the reply has been already sent from
* failure_route or from a callback and the timer has been already
@ -2050,7 +2067,8 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch,
}
if (local_winner>=0 && winning_code>=200 ) {
DBG("DEBUG: local transaction completed\n");
DBG("DEBUG: local transaction completed %d/%d (totag retr: %d/%d)\n",
winning_code, local_winner, totag_retr, t->tmcb_hl.reg_types);
if (!totag_retr) {
if (unlikely(has_tran_tmcbs(t,TMCB_LOCAL_COMPLETED) ))
run_trans_callbacks( TMCB_LOCAL_COMPLETED, t, 0,
@ -2285,10 +2303,21 @@ int reply_received( struct sip_msg *p_msg )
backup_xavps = xavp_set_list(&t->xavps_list);
#endif
setbflagsval(0, uac->branch_flags);
if(msg_status>last_uac_status) {
/* current response (msg) status is higher that the last received
* on the same branch - set it temporarily so functions in onreply_route
* can access it (e.g., avoid sending CANCEL by forcing another t_relply()
* in onreply_route when a negative sip response was received) */
uac->last_received = msg_status;
}
/* Pre- and post-script callbacks have already
* been executed by the core. (Miklos)
*/
run_top_route(onreply_rt.rlist[onreply_route], p_msg, &ctx);
/* restore brach last_received as before executing onreply_route */
uac->last_received = last_uac_status;
/* transfer current message context back to t */
if (t->uas.request) t->uas.request->flags=p_msg->flags;
getbflagsval(0, &uac->branch_flags);

@ -74,6 +74,11 @@ int t_suspend(struct sip_msg *msg,
ser_error = E_CANCELED;
return 1;
}
if (t->uas.status >= 200) {
LM_DBG("trasaction sent out a final response already - %d\n",
t->uas.status);
return -3;
}
if (msg->first_line.type != SIP_REPLY) {
/* send a 100 Trying reply, because the INVITE processing
@ -106,10 +111,10 @@ int t_suspend(struct sip_msg *msg,
* - failure route to be executed if the branch is not continued
* before timeout */
t->uac[t->async_backup.blind_uac].on_failure = t->on_failure;
t->flags |= T_ASYNC_SUSPENDED;
} else {
LM_DBG("this is a suspend on reply - setting msg flag to SUSPEND\n");
msg->msg_flags |= FL_RPL_SUSPENDED;
t->flags |= T_ASYNC_SUSPENDED;
/* this is a reply suspend find which branch */
if (t_check( msg , &branch )==-1){
@ -131,6 +136,7 @@ int t_suspend(struct sip_msg *msg,
LM_DBG("saving transaction data\n");
t->uac[branch].reply->flags = msg->flags;
t->flags |= T_ASYNC_SUSPENDED;
}
*hash_index = t->hash_index;
@ -176,7 +182,13 @@ int t_continue(unsigned int hash_index, unsigned int label,
return -1;
}
if (!(t->flags & T_ASYNC_SUSPENDED)) {
LM_WARN("transaction is not suspended [%u:%u]\n", hash_index, label);
return -2;
}
if (t->flags & T_CANCELED) {
t->flags &= ~T_ASYNC_SUSPENDED;
/* The transaction has already been canceled,
* needless to continue */
UNREF(t); /* t_unref would kill the transaction */
@ -219,6 +231,7 @@ int t_continue(unsigned int hash_index, unsigned int label,
/* Either t_continue() has already been
* called or the branch has already timed out.
* Needless to continue. */
t->flags &= ~T_ASYNC_SUSPENDED;
UNLOCK_ASYNC_CONTINUE(t);
UNREF(t); /* t_unref would kill the transaction */
return 1;
@ -298,7 +311,13 @@ int t_continue(unsigned int hash_index, unsigned int label,
LM_DBG("continuing from a suspended reply"
" - resetting the suspend branch flag\n");
if (t->uac[branch].reply) {
t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
} else {
LM_WARN("no reply in t_continue for branch. not much we can do\n");
return 0;
}
if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;
faked_env( t, t->uac[branch].reply, 1);
@ -437,9 +456,14 @@ done:
sip_msg_free(t->uac[branch].reply);
t->uac[branch].reply = 0;
}
/*This transaction is no longer suspended so unsetting the SUSPEND flag*/
t->flags &= ~T_ASYNC_SUSPENDED;
return 0;
kill_trans:
t->flags &= ~T_ASYNC_SUSPENDED;
/* The script has hopefully set the error code. If not,
* let us reply with a default error. */
if ((kill_transaction_unsafe(t,

@ -16,7 +16,15 @@ Alex Balashov
<abalashov@evaristesys.com>
Edited by
Richard Fuchs
<rfuchs@sipwise.com>
Copyright © 2012 asipto.com
Copyright © 2012 Sipwise GmbH
__________________________________________________________________
Table of Contents
@ -138,7 +146,11 @@ modparam("tmrec", "separator", ";")
subsequent intervals do not overlap. For non-recurring intervals,
durations of any positive length are permitted. Zero-length
duration means "forever". Negative-length durations are not
allowed. See RFC 2445 for the format of duration.
allowed.
See RFC 2445 for the format of duration. In short for common cases
when the duration doesn't exeed a data, it must start with PT
followed by the value for hours, minutes or seconds - e.g., a
duration of 8 hours must be written as PT8H.
* frequency - can be one of the following values: "daily" - specify
repeating periods based on an interval of a day or more; "weekly" -
specify repeating periods based on an interval of a week or more;
@ -208,7 +220,7 @@ modparam("tmrec", "separator", ";")
Next is an example of evaluating multiple Byxxx parameters.
startdate="20100101T093000" duration="10H30M" frequency="yearly"
startdate="20100101T093000" duration="PT10H30M" frequency="yearly"
interval="4" bymonth="3" byday="SU"
First, the interval="4" would be applied to frequency="yearly" to match

@ -126,9 +126,14 @@ modparam("tmrec", "separator", ";")
For a recurring interval, the <quote>duration</quote> parameter MUST
be small enough such that subsequent intervals do not overlap.
For non-recurring intervals, durations of any positive length are
permitted. Zero-length duration means <quote>forever</quote>.
Negative-length durations are not allowed. See RFC 2445 for
the format of duration.
permitted. Zero-length duration means <quote>forever</quote>.
Negative-length durations are not allowed.
</para>
<para>
See RFC 2445 for the format of duration. In short for common cases
when the duration doesn't exeed a data, it must start with PT
followed by the value for hours, minutes or seconds - e.g., a
duration of 8 hours must be written as PT8H.
</para>
</listitem>
<listitem>
@ -253,7 +258,7 @@ modparam("tmrec", "separator", ";")
Next is an example of evaluating multiple Byxxx parameters.
</para>
<para>
startdate=<quote>20100101T093000</quote> duration=<quote>10H30M</quote>
startdate=<quote>20100101T093000</quote> duration=<quote>PT10H30M</quote>
frequency=<quote>yearly</quote> interval=<quote>4</quote>
bymonth=<quote>3</quote> byday=<quote>SU</quote>
</para>

@ -44,8 +44,6 @@ static struct _pv_tmx_data _pv_treq;
static struct _pv_tmx_data _pv_trpl;
static struct _pv_tmx_data _pv_tinv;
static str _empty_str = {"", 0};
void pv_tmx_data_init(void)
{
memset(&_pv_treq, 0, sizeof(struct _pv_tmx_data));
@ -442,6 +440,7 @@ int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
pv_value_t *res)
{
struct cell *t;
tm_ctx_t *tcx = 0;
int branch;
if(msg==NULL || res==NULL)
@ -451,7 +450,7 @@ int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
if ( (t=_tmx_tmb.t_gett())==0) {
/* no T */
res->rs = _empty_str;
return pv_get_strempty(msg, param, res);
} else {
switch (get_route_type()) {
case FAILURE_ROUTE:
@ -460,18 +459,27 @@ int pv_get_tm_reply_ruid(struct sip_msg *msg, pv_param_t *param,
if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
LM_CRIT("no picked branch (%d) for a final response"
" in MODE_ONFAILURE\n", branch);
return -1;
return pv_get_strempty(msg, param, res);
}
res->rs = t->uac[branch].ruid;
LM_DBG("reply ruid is [%.*s]\n", t->uac[branch].ruid.len, t->uac[branch].ruid.s);
return pv_get_strval(msg, param, res, &t->uac[branch].ruid);
break;
case TM_ONREPLY_ROUTE:
tcx = _tmx_tmb.tm_ctx_get();
if(tcx == NULL) {
return pv_get_strempty(msg, param, res);
}
branch = tcx->branch_index;
if(branch<0 || branch>=t->nr_of_outgoings) {
return pv_get_strempty(msg, param, res);
}
LM_DBG("reply ruid is [%.*s]\n", t->uac[branch].ruid.len, t->uac[branch].ruid.s);
return pv_get_strval(msg, param, res, &t->uac[branch].ruid);
default:
LM_ERR("unsupported route_type %d\n", get_route_type());
return -1;
return pv_get_strempty(msg, param, res);
}
}
LM_DBG("reply ruid is [%.*s]\n", res->rs.len, res->rs.s);
res->flags = PV_VAL_STR;
return 0;
}
int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
@ -484,6 +492,14 @@ int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
if(msg==NULL || res==NULL)
return -1;
switch (get_route_type()) {
case CORE_ONREPLY_ROUTE:
case TM_ONREPLY_ROUTE:
/* use the status of the current reply */
code = msg->first_line.u.reply.statuscode;
goto done;
}
/* first get the transaction */
if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
if ( (t=_tmx_tmb.t_gett())==0) {
@ -496,16 +512,6 @@ int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
/* use the status of the last sent reply */
code = t->uas.status;
break;
case CORE_ONREPLY_ROUTE:
/* t_check() above has the side effect of setting T and
REFerencing T => we must unref and unset it for the
main/core onreply_route. */
_tmx_tmb.t_unref(msg);
/* no break */
case TM_ONREPLY_ROUTE:
/* use the status of the current reply */
code = msg->first_line.u.reply.statuscode;
break;
case FAILURE_ROUTE:
case BRANCH_FAILURE_ROUTE:
/* use the status of the winning reply */
@ -518,17 +524,16 @@ int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
}
break;
default:
LM_ERR("unsupported route_type %d\n", get_route_type());
LM_INFO("unsupported route_type %d - code set to 0\n",
get_route_type());
code = 0;
}
}
LM_DBG("reply code is <%d>\n",code);
res->rs.s = int2str( code, &res->rs.len);
done:
LM_DBG("reply code is <%d>\n", code);
return pv_get_sintval(msg, param, res, code);
res->ri = code;
res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
return 0;
}
@ -546,7 +551,7 @@ int pv_get_tm_reply_reason(struct sip_msg *msg, pv_param_t *param,
if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
if ( (t=_tmx_tmb.t_gett())==0) {
/* no T */
res->rs = _empty_str;
return pv_get_strempty(msg, param, res);
} else {
switch (get_route_type()) {
case CORE_ONREPLY_ROUTE:

@ -638,7 +638,7 @@ static int w_t_continue(struct sip_msg* msg, char *idx, char *lbl, char *rtn)
if(_tmx_tmb.t_continue(tindex, tlabel, act)<0)
{
LM_ERR("resuming the processing of transaction [%u:%u] failed\n",
LM_WARN("resuming the processing of transaction [%u:%u] failed\n",
tindex, tlabel);
return -1;
}

@ -210,7 +210,10 @@ int tmx_check_pretran(sip_msg_t *msg)
LM_ERR("failed to parse required headers\n");
return -1;
}
if(msg->cseq==NULL || msg->cseq->parsed==NULL) {
LM_ERR("failed to parse cseq headers\n");
return -1;
}
if(get_cseq(msg)->method_id==METHOD_ACK
|| get_cseq(msg)->method_id==METHOD_CANCEL) {
LM_DBG("no pre-transaction management for ACK or CANCEL\n");
@ -224,6 +227,10 @@ int tmx_check_pretran(sip_msg_t *msg)
LM_ERR("failed to get From header\n");
return -1;
}
if (msg->callid==NULL || msg->callid->body.s==NULL) {
LM_ERR("failed to parse callid headers\n");
return -1;
}
vbr = msg->via1->branch;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save