mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1414 lines
36 KiB
1414 lines
36 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2012 Andrew Mortensen
|
|
*
|
|
* This file is part of the sca module for sip-router, a free SIP server.
|
|
*
|
|
* The sca module is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* The sca module is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*
|
|
*/
|
|
#include "sca_common.h"
|
|
|
|
#include "../../lib/kcore/strcommon.h"
|
|
|
|
#include "sca.h"
|
|
#include "sca_appearance.h"
|
|
#include "sca_hash.h"
|
|
#include "sca_notify.h"
|
|
#include "sca_util.h"
|
|
|
|
const str SCA_APPEARANCE_INDEX_STR = STR_STATIC_INIT( "appearance-index" );
|
|
const str SCA_APPEARANCE_STATE_STR = STR_STATIC_INIT( "appearance-state" );
|
|
const str SCA_APPEARANCE_URI_STR = STR_STATIC_INIT( "appearance-uri" );
|
|
|
|
const str SCA_APPEARANCE_STATE_STR_IDLE = STR_STATIC_INIT( "idle" );
|
|
const str SCA_APPEARANCE_STATE_STR_SEIZED = STR_STATIC_INIT( "seized" );
|
|
const str SCA_APPEARANCE_STATE_STR_PROGRESSING = STR_STATIC_INIT("progressing");
|
|
const str SCA_APPEARANCE_STATE_STR_ALERTING = STR_STATIC_INIT( "alerting" );
|
|
const str SCA_APPEARANCE_STATE_STR_ACTIVE = STR_STATIC_INIT( "active" );
|
|
const str SCA_APPEARANCE_STATE_STR_HELD = STR_STATIC_INIT( "held" );
|
|
const str SCA_APPEARANCE_STATE_STR_HELD_PRIVATE = STR_STATIC_INIT("held-private");
|
|
const str SCA_APPEARANCE_STATE_STR_UNKNOWN = STR_STATIC_INIT( "unknown" );
|
|
|
|
|
|
/* STR_ACTIVE is repeated, once for ACTIVE_PENDING, once for ACTIVE */
|
|
const str *state_names[] = {
|
|
&SCA_APPEARANCE_STATE_STR_IDLE,
|
|
&SCA_APPEARANCE_STATE_STR_SEIZED,
|
|
&SCA_APPEARANCE_STATE_STR_PROGRESSING,
|
|
&SCA_APPEARANCE_STATE_STR_ALERTING,
|
|
&SCA_APPEARANCE_STATE_STR_ACTIVE,
|
|
&SCA_APPEARANCE_STATE_STR_ACTIVE,
|
|
&SCA_APPEARANCE_STATE_STR_HELD,
|
|
&SCA_APPEARANCE_STATE_STR_HELD_PRIVATE,
|
|
};
|
|
#define SCA_APPEARANCE_STATE_NAME_COUNT \
|
|
( sizeof( state_names ) / sizeof( state_names[ 0 ] ))
|
|
|
|
void
|
|
sca_appearance_state_to_str( int state, str *state_str )
|
|
{
|
|
assert( state_str != NULL );
|
|
|
|
if ( state >= SCA_APPEARANCE_STATE_NAME_COUNT || state < 0 ) {
|
|
state_str->len = SCA_APPEARANCE_STATE_STR_UNKNOWN.len;
|
|
state_str->s = SCA_APPEARANCE_STATE_STR_UNKNOWN.s;
|
|
|
|
return;
|
|
}
|
|
|
|
state_str->len = state_names[ state ]->len;
|
|
state_str->s = state_names[ state ]->s;
|
|
}
|
|
|
|
int
|
|
sca_appearance_state_from_str( str *state_str )
|
|
{
|
|
int state;
|
|
|
|
assert( state_str != NULL );
|
|
|
|
for ( state = 0; state < SCA_APPEARANCE_STATE_NAME_COUNT; state++ ) {
|
|
if ( SCA_STR_EQ( state_str, state_names[ state ] )) {
|
|
break;
|
|
}
|
|
}
|
|
if ( state >= SCA_APPEARANCE_STATE_NAME_COUNT ) {
|
|
state = SCA_APPEARANCE_STATE_UNKNOWN;
|
|
}
|
|
|
|
return( state );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_create( int appearance_index, str *owner_uri )
|
|
{
|
|
sca_appearance *new_appearance = NULL;
|
|
|
|
/*
|
|
* we use multiple shm_malloc calls here because uri, owner,
|
|
* dialog and callee are mutable. could also shm_malloc a big
|
|
* block and divide it among the strs....
|
|
*/
|
|
|
|
new_appearance = (sca_appearance *)shm_malloc( sizeof( sca_appearance ));
|
|
if ( new_appearance == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc new sca_appearance for %.*s, index %d",
|
|
STR_FMT( owner_uri ), appearance_index );
|
|
goto error;
|
|
}
|
|
memset( new_appearance, 0, sizeof( sca_appearance ));
|
|
|
|
new_appearance->owner.s = (char *)shm_malloc( owner_uri->len );
|
|
if ( new_appearance->owner.s == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc space for owner %.*s, index %d",
|
|
STR_FMT( owner_uri ), appearance_index );
|
|
goto error;
|
|
}
|
|
SCA_STR_COPY( &new_appearance->owner, owner_uri );
|
|
|
|
new_appearance->index = appearance_index;
|
|
new_appearance->times.ctime = time( NULL );
|
|
sca_appearance_update_state_unsafe( new_appearance,
|
|
SCA_APPEARANCE_STATE_IDLE );
|
|
new_appearance->next = NULL;
|
|
|
|
return( new_appearance );
|
|
|
|
error:
|
|
if ( new_appearance != NULL ) {
|
|
if ( !SCA_STR_EMPTY( &new_appearance->owner )) {
|
|
shm_free( new_appearance->owner.s );
|
|
}
|
|
|
|
shm_free( new_appearance );
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
void
|
|
sca_appearance_free( sca_appearance *appearance )
|
|
{
|
|
if ( appearance != NULL ) {
|
|
if ( appearance->owner.s != NULL ) {
|
|
shm_free( appearance->owner.s );
|
|
}
|
|
if ( appearance->uri.s != NULL ) {
|
|
shm_free( appearance->uri.s );
|
|
}
|
|
if ( appearance->dialog.id.s != NULL ) {
|
|
shm_free( appearance->dialog.id.s );
|
|
}
|
|
|
|
if ( appearance->prev_owner.s != NULL ) {
|
|
shm_free( appearance->prev_owner.s );
|
|
}
|
|
if ( appearance->prev_callee.s != NULL ) {
|
|
shm_free( appearance->prev_callee.s );
|
|
}
|
|
if ( appearance->prev_dialog.id.s != NULL ) {
|
|
shm_free( appearance->prev_dialog.id.s );
|
|
}
|
|
|
|
shm_free( appearance );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* assumes slot for app_entries is locked.
|
|
*
|
|
* appearance-index values are 1-indexed.
|
|
* return values:
|
|
* -1: error
|
|
* >=1: index reserved for claimant
|
|
*/
|
|
static int
|
|
sca_appearance_list_next_available_index_unsafe( sca_appearance_list *app_list )
|
|
{
|
|
sca_appearance *app_cur;
|
|
int idx = 1;
|
|
|
|
assert( app_list != NULL );
|
|
|
|
for ( app_cur = app_list->appearances; app_cur != NULL;
|
|
app_cur = app_cur->next, idx++ ) {
|
|
if ( idx < app_cur->index ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( idx );
|
|
}
|
|
|
|
static sca_appearance_list *
|
|
sca_appearance_list_create( sca_mod *scam, str *aor )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
int len;
|
|
|
|
len = sizeof( sca_appearance_list ) + aor->len;
|
|
app_list = (sca_appearance_list *)shm_malloc( len );
|
|
if ( app_list == NULL ) {
|
|
LM_ERR( "Failed to shm_malloc sca_appearance_list for %.*s",
|
|
STR_FMT( aor ));
|
|
return( NULL );
|
|
}
|
|
memset( app_list, 0, sizeof( sca_appearance_list ));
|
|
|
|
len = sizeof( sca_appearance_list );
|
|
app_list->aor.s = (char *)app_list + len;
|
|
SCA_STR_COPY( &app_list->aor, aor );
|
|
|
|
return( app_list );
|
|
}
|
|
|
|
sca_appearance_list *
|
|
sca_appearance_list_for_line( sca_mod *scam, str *aor )
|
|
{
|
|
//sca_appearance_list
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
void
|
|
sca_appearance_list_insert_appearance( sca_appearance_list *app_list,
|
|
sca_appearance *app )
|
|
{
|
|
sca_appearance **cur;
|
|
|
|
assert( app_list != NULL );
|
|
assert( app != NULL );
|
|
|
|
app->appearance_list = app_list;
|
|
|
|
for ( cur = &app_list->appearances; *cur != NULL; cur = &(*cur)->next ) {
|
|
if ( app->index < (*cur)->index ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
app->next = *cur;
|
|
*cur = app;
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_list_unlink_index( sca_appearance_list *app_list, int idx )
|
|
{
|
|
sca_appearance *app = NULL;
|
|
sca_appearance **cur;
|
|
|
|
assert( app_list != NULL );
|
|
assert( idx > 0 );
|
|
|
|
for ( cur = &app_list->appearances; *cur != NULL; cur = &(*cur)->next ) {
|
|
if ((*cur)->index == idx ) {
|
|
app = *cur;
|
|
app->appearance_list = NULL;
|
|
|
|
*cur = (*cur)->next;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( app == NULL ) {
|
|
LM_ERR( "Tried to remove inactive %.*s appearance at index %d",
|
|
STR_FMT( &app_list->aor ), idx );
|
|
}
|
|
|
|
return( app );
|
|
}
|
|
|
|
int
|
|
sca_appearance_list_unlink_appearance( sca_appearance_list *app_list,
|
|
sca_appearance **app )
|
|
{
|
|
sca_appearance **cur;
|
|
int rc = 0;
|
|
|
|
assert( app_list != NULL );
|
|
assert( app != NULL && *app != NULL );
|
|
|
|
for ( cur = &app_list->appearances; *cur != NULL; cur = &(*cur)->next ) {
|
|
if ( *cur == *app ) {
|
|
*cur = (*cur)->next;
|
|
|
|
(*app)->appearance_list = NULL;
|
|
(*app)->next = NULL;
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_appearance_list_aor_cmp( str *aor, void *cmp_value )
|
|
{
|
|
sca_appearance_list *app_list = (sca_appearance_list *)cmp_value;
|
|
int cmp;
|
|
|
|
if (( cmp = aor->len - app_list->aor.len ) != 0 ) {
|
|
return( cmp );
|
|
}
|
|
|
|
return( memcmp( aor->s, app_list->aor.s, aor->len ));
|
|
}
|
|
|
|
void
|
|
sca_appearance_list_print( void *value )
|
|
{
|
|
sca_appearance_list *app_list = (sca_appearance_list *)value;
|
|
sca_appearance *app;
|
|
str state_str = STR_NULL;
|
|
|
|
LM_INFO( "Appearance state for AoR %.*s:", STR_FMT( &app_list->aor ));
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
sca_appearance_state_to_str( app->state, &state_str );
|
|
LM_INFO( "index: %d, state: %.*s, uri: %.*s, owner: %.*s, "
|
|
"callee: %.*s, dialog: %.*s;%.*s;%.*s",
|
|
app->index, STR_FMT( &state_str ),
|
|
STR_FMT( &app->uri ), STR_FMT( &app->owner ),
|
|
STR_FMT( &app->callee ), STR_FMT( &app->dialog.call_id ),
|
|
STR_FMT( &app->dialog.from_tag ),
|
|
STR_FMT( &app->dialog.to_tag ));
|
|
}
|
|
}
|
|
|
|
void
|
|
sca_appearance_list_free( void *value )
|
|
{
|
|
sca_appearance_list *app_list = (sca_appearance_list *)value;
|
|
sca_appearance *app, *app_tmp;
|
|
|
|
LM_DBG( "Freeing appearance list for AoR %.*s", STR_FMT( &app_list->aor ));
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app_tmp ) {
|
|
app_tmp = app->next;
|
|
|
|
shm_free( app );
|
|
}
|
|
|
|
shm_free( app_list );
|
|
}
|
|
|
|
int
|
|
sca_appearance_register( sca_mod *scam, str *aor )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
int rc = -1;
|
|
|
|
assert( scam != NULL );
|
|
assert( aor != NULL );
|
|
|
|
if ( sca_uri_is_shared_appearance( scam, aor )) {
|
|
/* we've already registered */
|
|
rc = 0;
|
|
goto done;
|
|
}
|
|
|
|
app_list = sca_appearance_list_create( scam, aor );
|
|
if ( app_list == NULL ) {
|
|
goto done;
|
|
}
|
|
|
|
if ( sca_hash_table_kv_insert( scam->appearances, aor, app_list,
|
|
sca_appearance_list_aor_cmp,
|
|
sca_appearance_list_print,
|
|
sca_appearance_list_free ) < 0 ) {
|
|
LM_ERR( "sca_appearance_register: failed to insert appearance list "
|
|
"for %.*s", STR_FMT( aor ));
|
|
goto done;
|
|
}
|
|
|
|
rc = 1;
|
|
|
|
done:
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_appearance_unregister( sca_mod *scam, str *aor )
|
|
{
|
|
int rc = 0;
|
|
|
|
assert( scam != NULL );
|
|
assert( aor != NULL );
|
|
|
|
if ( sca_uri_is_shared_appearance( scam, aor )) {
|
|
if (( rc = sca_hash_table_kv_delete( scam->appearances, aor )) == 0 ) {
|
|
rc = 1;
|
|
LM_INFO( "unregistered SCA AoR %.*s", STR_FMT( aor ));
|
|
}
|
|
}
|
|
|
|
return( rc );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_seize_index_unsafe( sca_mod *scam, str *aor, str *owner_uri,
|
|
int app_idx, int slot_idx, int *seize_error )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app = NULL;
|
|
sca_hash_slot *slot;
|
|
int error = SCA_APPEARANCE_ERR_UNKNOWN;
|
|
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
if ( app_list == NULL ) {
|
|
LM_ERR( "sca_appearance_seize_index_unsafe: no appearance list for "
|
|
"%.*s", STR_FMT( aor ));
|
|
goto done;
|
|
}
|
|
|
|
if ( app_idx <= 0 ) {
|
|
app_idx = sca_appearance_list_next_available_index_unsafe( app_list );
|
|
}
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
if ( app->index >= app_idx ) {
|
|
break;
|
|
}
|
|
}
|
|
if ( app != NULL && app->index == app_idx ) {
|
|
/* attempt to seize in-use appearance-index */
|
|
error = SCA_APPEARANCE_ERR_INDEX_UNAVAILABLE;
|
|
app = NULL;
|
|
goto done;
|
|
}
|
|
|
|
app = sca_appearance_create( app_idx, owner_uri );
|
|
if ( app == NULL ) {
|
|
LM_ERR( "Failed to create new appearance for %.*s at index %d",
|
|
STR_FMT( owner_uri ), app_idx );
|
|
error = SCA_APPEARANCE_ERR_MALLOC;
|
|
goto done;
|
|
}
|
|
sca_appearance_update_state_unsafe( app, SCA_APPEARANCE_STATE_SEIZED );
|
|
|
|
sca_appearance_list_insert_appearance( app_list, app );
|
|
|
|
error = SCA_APPEARANCE_OK;
|
|
|
|
done:
|
|
if ( seize_error ) {
|
|
*seize_error = error;
|
|
}
|
|
|
|
return( app );
|
|
}
|
|
|
|
int
|
|
sca_appearance_seize_index( sca_mod *scam, str *aor, int idx, str *owner_uri )
|
|
{
|
|
sca_appearance *app;
|
|
int slot_idx;
|
|
int app_idx = -1;
|
|
int error = SCA_APPEARANCE_OK;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
app = sca_appearance_seize_index_unsafe( scam, aor, owner_uri,
|
|
idx, slot_idx, &error );
|
|
if ( app != NULL ) {
|
|
app_idx = app->index;
|
|
}
|
|
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
if ( error == SCA_APPEARANCE_ERR_INDEX_UNAVAILABLE ) {
|
|
app_idx = SCA_APPEARANCE_INDEX_UNAVAILABLE;
|
|
}
|
|
|
|
return( app_idx );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_seize_next_available_unsafe( sca_mod *scam, str *aor,
|
|
str *owner_uri, int slot_idx )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app = NULL;
|
|
sca_hash_slot *slot;
|
|
int idx = -1;
|
|
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
if ( app_list == NULL ) {
|
|
app_list = sca_appearance_list_create( scam, aor );
|
|
if ( app_list == NULL ) {
|
|
goto done;
|
|
}
|
|
|
|
if ( sca_hash_table_slot_kv_insert_unsafe( slot, app_list,
|
|
sca_appearance_list_aor_cmp,
|
|
sca_appearance_list_print,
|
|
sca_appearance_list_free ) < 0 ) {
|
|
LM_ERR( "Failed to insert appearance list for %.*s",
|
|
STR_FMT( aor ));
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* XXX this grows without bound. add modparam to set a hard limit */
|
|
idx = sca_appearance_list_next_available_index_unsafe( app_list );
|
|
/* XXX check idx > any configured max appearance index */
|
|
|
|
app = sca_appearance_create( idx, owner_uri );
|
|
if ( app == NULL ) {
|
|
LM_ERR( "Failed to create new appearance for %.*s at index %d",
|
|
STR_FMT( owner_uri ), idx );
|
|
goto done;
|
|
}
|
|
sca_appearance_update_state_unsafe( app, SCA_APPEARANCE_STATE_SEIZED );
|
|
|
|
sca_appearance_list_insert_appearance( app_list, app );
|
|
|
|
done:
|
|
return( app );
|
|
}
|
|
|
|
int
|
|
sca_appearance_seize_next_available_index( sca_mod *scam, str *aor,
|
|
str *owner_uri )
|
|
{
|
|
sca_appearance *app;
|
|
int slot_idx;
|
|
int idx = -1;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
app = sca_appearance_seize_next_available_unsafe( scam, aor,
|
|
owner_uri, slot_idx );
|
|
if ( app != NULL ) {
|
|
idx = app->index;
|
|
}
|
|
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
return( idx );
|
|
}
|
|
|
|
void
|
|
sca_appearance_update_state_unsafe( sca_appearance *app, int state )
|
|
{
|
|
assert( app != NULL );
|
|
|
|
app->state = state;
|
|
app->times.mtime = time( NULL );
|
|
}
|
|
|
|
int
|
|
sca_appearance_update_owner_unsafe( sca_appearance *app, str *owner )
|
|
{
|
|
assert( app != NULL );
|
|
assert( owner != NULL );
|
|
|
|
if ( !SCA_STR_EMPTY( &app->owner )) {
|
|
if ( app->prev_owner.s != NULL ) {
|
|
shm_free( app->prev_owner.s );
|
|
}
|
|
app->prev_owner.s = app->owner.s;
|
|
app->prev_owner.len = app->owner.len;
|
|
}
|
|
|
|
app->owner.s = (char *)shm_malloc( owner->len );
|
|
if ( app->owner.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_owner_unsafe: shm_malloc for new "
|
|
"owner %.*s failed: out of memory", STR_FMT( owner ));
|
|
goto error;
|
|
}
|
|
SCA_STR_COPY( &app->owner, owner );
|
|
|
|
return( 1 );
|
|
|
|
error:
|
|
/* restore owner */
|
|
app->owner.s = app->prev_owner.s;
|
|
app->owner.len = app->prev_owner.len;
|
|
memset( &app->prev_owner, 0, sizeof( str ));
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
int
|
|
sca_appearance_update_callee_unsafe( sca_appearance *app, str *callee )
|
|
{
|
|
assert( app != NULL );
|
|
assert( callee != NULL );
|
|
|
|
if ( !SCA_STR_EMPTY( &app->callee )) {
|
|
if ( app->prev_callee.s != NULL ) {
|
|
shm_free( app->prev_callee.s );
|
|
}
|
|
app->prev_callee.s = app->callee.s;
|
|
app->prev_callee.len = app->callee.len;
|
|
}
|
|
|
|
app->callee.s = (char *)shm_malloc( callee->len );
|
|
if ( app->callee.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_owner_unsafe: shm_malloc for new "
|
|
"callee %.*s failed: out of memory", STR_FMT( callee ));
|
|
goto error;
|
|
}
|
|
SCA_STR_COPY( &app->callee, callee );
|
|
|
|
return( 1 );
|
|
|
|
error:
|
|
/* restore callee */
|
|
app->callee.s = app->prev_callee.s;
|
|
app->callee.len = app->prev_callee.len;
|
|
memset( &app->prev_callee, 0, sizeof( str ));
|
|
|
|
return( -1 );
|
|
}
|
|
int
|
|
sca_appearance_update_dialog_unsafe( sca_appearance *app, str *call_id,
|
|
str *from_tag, str *to_tag )
|
|
{
|
|
int len;
|
|
|
|
assert( app != NULL );
|
|
assert( call_id != NULL );
|
|
assert( from_tag != NULL );
|
|
|
|
if ( !SCA_STR_EMPTY( &app->dialog.id )) {
|
|
if ( app->prev_dialog.id.s != NULL ) {
|
|
shm_free( app->prev_dialog.id.s );
|
|
}
|
|
app->prev_dialog.id.s = app->dialog.id.s;
|
|
app->prev_dialog.id.len = app->dialog.id.len;
|
|
|
|
app->prev_dialog.call_id.s = app->dialog.call_id.s;
|
|
app->prev_dialog.call_id.len = app->dialog.call_id.len;
|
|
|
|
app->prev_dialog.from_tag.s = app->dialog.from_tag.s;
|
|
app->prev_dialog.from_tag.len = app->dialog.from_tag.len;
|
|
|
|
app->prev_dialog.to_tag.s = app->dialog.to_tag.s;
|
|
app->prev_dialog.to_tag.len = app->dialog.to_tag.len;
|
|
}
|
|
|
|
len = call_id->len + from_tag->len;
|
|
if ( !SCA_STR_EMPTY( to_tag )) {
|
|
len += to_tag->len;
|
|
}
|
|
|
|
app->dialog.id.s = (char *)shm_malloc( len );
|
|
if ( app->dialog.id.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_dialog_unsafe: shm_malloc new dialog "
|
|
"failed: out of memory" );
|
|
goto error;
|
|
}
|
|
SCA_STR_COPY( &app->dialog.id, call_id );
|
|
SCA_STR_APPEND( &app->dialog.id, from_tag );
|
|
|
|
app->dialog.call_id.s = app->dialog.id.s;
|
|
app->dialog.call_id.len = call_id->len;
|
|
|
|
app->dialog.from_tag.s = app->dialog.id.s + call_id->len;
|
|
app->dialog.from_tag.len = from_tag->len;
|
|
|
|
app->dialog.to_tag.s = app->dialog.id.s + call_id->len + from_tag->len;
|
|
app->dialog.to_tag.len = to_tag->len;
|
|
|
|
return( 1 );
|
|
|
|
error:
|
|
/* restore dialog */
|
|
app->prev_dialog.id.s = app->dialog.id.s;
|
|
app->prev_dialog.id.len = app->dialog.id.len;
|
|
|
|
app->prev_dialog.call_id.s = app->dialog.call_id.s;
|
|
app->prev_dialog.call_id.len = app->dialog.call_id.len;
|
|
|
|
app->prev_dialog.from_tag.s = app->dialog.from_tag.s;
|
|
app->prev_dialog.from_tag.len = app->dialog.from_tag.len;
|
|
|
|
app->prev_dialog.to_tag.s = app->dialog.to_tag.s;
|
|
app->prev_dialog.to_tag.len = app->dialog.to_tag.len;
|
|
|
|
memset( &app->prev_dialog, 0, sizeof( sca_dialog ));
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
int
|
|
sca_appearance_update_unsafe( sca_appearance *app, int state, str *display,
|
|
str *uri, sca_dialog *dialog, str *owner, str *callee )
|
|
{
|
|
int rc = SCA_APPEARANCE_OK;
|
|
int len;
|
|
|
|
if ( state != SCA_APPEARANCE_STATE_UNKNOWN ) {
|
|
sca_appearance_update_state_unsafe( app, state );
|
|
}
|
|
|
|
if ( !SCA_STR_EMPTY( uri )) {
|
|
if ( !SCA_STR_EMPTY( &app->uri )) {
|
|
/* the uri str's s member is shm_malloc'd separately */
|
|
shm_free( app->uri.s );
|
|
memset( &app->uri, 0, sizeof( str ));
|
|
}
|
|
|
|
/* +2 for left & right carets surrounding URI */
|
|
len = uri->len + 2;
|
|
if ( !SCA_STR_EMPTY( display )) {
|
|
/* cheaper to scan string than shm_malloc 2x display? */
|
|
len += sca_uri_display_escapes_count( display );
|
|
/* +1 for space between display & uri */
|
|
len += display->len + 1;
|
|
}
|
|
app->uri.s = (char *)shm_malloc( len );
|
|
if ( app->uri.s == NULL ) {
|
|
LM_ERR( "shm_malloc %d bytes returned NULL", uri->len );
|
|
rc = SCA_APPEARANCE_ERR_MALLOC;
|
|
goto done;
|
|
}
|
|
|
|
if ( !SCA_STR_EMPTY( display )) {
|
|
/* copy escaped display information... */
|
|
app->uri.len = escape_common( app->uri.s, display->s,
|
|
display->len );
|
|
|
|
/* ... and add a space between it and the uri */
|
|
*(app->uri.s + app->uri.len) = ' ';
|
|
app->uri.len++;
|
|
}
|
|
|
|
*(app->uri.s + app->uri.len) = '<';
|
|
app->uri.len++;
|
|
|
|
SCA_STR_APPEND( &app->uri, uri );
|
|
|
|
*(app->uri.s + app->uri.len) = '>';
|
|
app->uri.len++;
|
|
}
|
|
|
|
if ( !SCA_DIALOG_EMPTY( dialog )) {
|
|
if ( !SCA_STR_EQ( &dialog->id, &app->dialog.id )) {
|
|
if ( app->dialog.id.s != NULL ) {
|
|
shm_free( app->dialog.id.s );
|
|
}
|
|
|
|
app->dialog.id.s = (char *)shm_malloc( dialog->id.len );
|
|
if ( app->dialog.id.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_unsafe: shm_malloc dialog id "
|
|
"failed: out of shared memory" );
|
|
/* XXX this seems bad enough to abort... */
|
|
return( -1 );
|
|
}
|
|
SCA_STR_COPY( &app->dialog.id, &dialog->id );
|
|
|
|
app->dialog.call_id.s = app->dialog.id.s;
|
|
app->dialog.call_id.len = dialog->call_id.len;
|
|
|
|
app->dialog.from_tag.s = app->dialog.id.s + dialog->call_id.len;
|
|
app->dialog.from_tag.len = dialog->from_tag.len;
|
|
|
|
if ( !SCA_STR_EMPTY( &dialog->to_tag )) {
|
|
app->dialog.to_tag.s = app->dialog.id.s +
|
|
dialog->call_id.len +
|
|
dialog->from_tag.len;
|
|
app->dialog.to_tag.len = dialog->to_tag.len;
|
|
} else {
|
|
app->dialog.to_tag.s = NULL;
|
|
app->dialog.to_tag.len = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* note these two blocks could be condensed and inlined */
|
|
if ( !SCA_STR_EMPTY( owner )) {
|
|
if ( !SCA_STR_EQ( &app->owner, owner )) {
|
|
if ( app->owner.s != NULL ) {
|
|
shm_free( app->owner.s );
|
|
}
|
|
|
|
app->owner.s = (char *)shm_malloc( owner->len );
|
|
if ( app->owner.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_unsafe: shm_malloc "
|
|
"appearance owner URI failed: out of shared memory" );
|
|
return( -1 );
|
|
}
|
|
SCA_STR_COPY( &app->owner, owner );
|
|
}
|
|
}
|
|
|
|
if ( !SCA_STR_EMPTY( callee )) {
|
|
if ( !SCA_STR_EQ( &app->callee, callee )) {
|
|
if ( app->callee.s != NULL ) {
|
|
shm_free( app->callee.s );
|
|
}
|
|
|
|
app->callee.s = (char *)shm_malloc( callee->len );
|
|
if ( app->callee.s == NULL ) {
|
|
LM_ERR( "sca_appearance_update_unsafe: shm_malloc "
|
|
"appearance callee URI failed: out of shared memory" );
|
|
return( -1 );
|
|
}
|
|
SCA_STR_COPY( &app->callee, callee );
|
|
}
|
|
}
|
|
|
|
done:
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_uri_is_shared_appearance( sca_mod *scam, str *aor )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_appearance_list *app_list;
|
|
int slot_idx;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
if ( app_list == NULL ) {
|
|
return( 0 );
|
|
}
|
|
|
|
return( 1 );
|
|
}
|
|
|
|
int
|
|
sca_uri_lock_shared_appearance( sca_mod *scam, str *aor )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_appearance_list *app_list;
|
|
int slot_idx;
|
|
|
|
if ( SCA_STR_EMPTY( aor )) {
|
|
return( -1 );
|
|
}
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
|
|
if ( app_list == NULL ) {
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
slot_idx = -1;
|
|
}
|
|
|
|
return( slot_idx );
|
|
}
|
|
|
|
int
|
|
sca_uri_lock_if_shared_appearance( sca_mod *scam, str *aor, int *slot_idx )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_appearance_list *app_list;
|
|
|
|
assert( slot_idx != NULL );
|
|
|
|
if ( SCA_STR_EMPTY( aor )) {
|
|
*slot_idx = -1;
|
|
return( 0 );
|
|
}
|
|
|
|
*slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, *slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, *slot_idx );
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
|
|
if ( app_list == NULL ) {
|
|
sca_hash_table_unlock_index( scam->appearances, *slot_idx );
|
|
*slot_idx = -1;
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
return( 1 );
|
|
}
|
|
|
|
int
|
|
sca_appearance_state_for_index( sca_mod *scam, str *aor, int idx )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app;
|
|
int slot_idx;
|
|
int state = SCA_APPEARANCE_STATE_UNKNOWN;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
if ( app_list == NULL ) {
|
|
LM_DBG( "%.*s has no in-use appearances", STR_FMT( aor ));
|
|
goto done;
|
|
}
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
if ( app->index == idx ) {
|
|
break;
|
|
}
|
|
}
|
|
if ( app == NULL ) {
|
|
LM_WARN( "%.*s appearance-index %d is not in use",
|
|
STR_FMT( aor ), idx );
|
|
goto done;
|
|
}
|
|
|
|
state = app->state;
|
|
|
|
done:
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
return( state );
|
|
}
|
|
|
|
int
|
|
sca_appearance_update_index( sca_mod *scam, str *aor, int idx,
|
|
int state, str *display, str *uri, sca_dialog *dialog )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app;
|
|
str state_str = STR_NULL;
|
|
int len;
|
|
int slot_idx;
|
|
int rc = SCA_APPEARANCE_ERR_UNKNOWN;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
sca_appearance_state_to_str( state, &state_str );
|
|
|
|
app_list = sca_hash_table_slot_kv_find_unsafe( slot, aor );
|
|
if ( app_list == NULL ) {
|
|
LM_WARN( "Cannot update %.*s index %d to state %.*s: %.*s has no "
|
|
"in-use appearances", STR_FMT( aor ), idx,
|
|
STR_FMT( &state_str ), STR_FMT( aor ));
|
|
rc = SCA_APPEARANCE_ERR_NOT_IN_USE;
|
|
goto done;
|
|
}
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
if ( app->index == idx ) {
|
|
break;
|
|
} else if ( idx == 0 ) {
|
|
if ( SCA_STR_EQ( &dialog->id, &app->dialog.id )) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( app == NULL ) {
|
|
LM_WARN( "Cannot update %.*s index %d to %.*s: index %d not in use",
|
|
STR_FMT( aor ), idx, STR_FMT( &state_str ), idx );
|
|
rc = SCA_APPEARANCE_ERR_INDEX_INVALID;
|
|
goto done;
|
|
}
|
|
|
|
if ( state != SCA_APPEARANCE_STATE_UNKNOWN && app->state != state ) {
|
|
sca_appearance_update_state_unsafe( app, state );
|
|
}
|
|
|
|
if ( !SCA_STR_EMPTY( uri )) {
|
|
if ( !SCA_STR_EMPTY( &app->uri )) {
|
|
/* the uri str's s member is shm_malloc'd separately */
|
|
shm_free( app->uri.s );
|
|
memset( &app->uri, 0, sizeof( str ));
|
|
}
|
|
|
|
/* +2 for left & right carets surrounding URI */
|
|
len = uri->len + 2;
|
|
if ( !SCA_STR_EMPTY( display )) {
|
|
/* cheaper to scan string than shm_malloc 2x display? */
|
|
len += sca_uri_display_escapes_count( display );
|
|
/* +1 for space between display & uri */
|
|
len += display->len + 1;
|
|
}
|
|
app->uri.s = (char *)shm_malloc( len );
|
|
if ( app->uri.s == NULL ) {
|
|
LM_ERR( "Failed to update %.*s index %d uri to %.*s: "
|
|
"shm_malloc %d bytes returned NULL",
|
|
STR_FMT( aor ), idx, STR_FMT( uri ), uri->len );
|
|
rc = SCA_APPEARANCE_ERR_MALLOC;
|
|
goto done;
|
|
}
|
|
|
|
if ( !SCA_STR_EMPTY( display )) {
|
|
/* copy escaped display information... */
|
|
app->uri.len = escape_common( app->uri.s, display->s,
|
|
display->len );
|
|
|
|
/* ... and add a space between it and the uri */
|
|
*(app->uri.s + app->uri.len) = ' ';
|
|
app->uri.len++;
|
|
}
|
|
|
|
*(app->uri.s + app->uri.len) = '<';
|
|
app->uri.len++;
|
|
|
|
SCA_STR_APPEND( &app->uri, uri );
|
|
|
|
*(app->uri.s + app->uri.len) = '>';
|
|
app->uri.len++;
|
|
}
|
|
|
|
if ( !SCA_DIALOG_EMPTY( dialog )) {
|
|
if ( !SCA_STR_EQ( &dialog->id, &app->dialog.id )) {
|
|
if ( app->dialog.id.s != NULL ) {
|
|
shm_free( app->dialog.id.s );
|
|
}
|
|
|
|
app->dialog.id.s = (char *)shm_malloc( dialog->id.len );
|
|
SCA_STR_COPY( &app->dialog.id, &dialog->id );
|
|
|
|
app->dialog.call_id.s = app->dialog.id.s;
|
|
app->dialog.call_id.len = dialog->call_id.len;
|
|
|
|
app->dialog.from_tag.s = app->dialog.id.s + dialog->call_id.len;
|
|
app->dialog.from_tag.len = dialog->from_tag.len;
|
|
|
|
if ( !SCA_STR_EMPTY( &dialog->to_tag )) {
|
|
app->dialog.to_tag.s = app->dialog.id.s +
|
|
dialog->call_id.len +
|
|
dialog->from_tag.len;
|
|
app->dialog.to_tag.len = dialog->to_tag.len;
|
|
} else {
|
|
app->dialog.to_tag.s = NULL;
|
|
app->dialog.to_tag.len = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = SCA_APPEARANCE_OK;
|
|
|
|
done:
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_appearance_release_index( sca_mod *scam, str *aor, int idx )
|
|
{
|
|
sca_hash_slot *slot;
|
|
sca_hash_entry *ent;
|
|
sca_appearance_list *app_list = NULL;
|
|
sca_appearance *app;
|
|
int slot_idx;
|
|
int rc = SCA_APPEARANCE_ERR_UNKNOWN;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
app_list = NULL;
|
|
for ( ent = slot->entries; ent != NULL; ent = ent->next ) {
|
|
if ( ent->compare( aor, ent->value ) == 0 ) {
|
|
app_list = (sca_appearance_list *)ent->value;
|
|
break;
|
|
}
|
|
}
|
|
if ( app_list == NULL ) {
|
|
LM_ERR( "No appearances for %.*s", STR_FMT( aor ));
|
|
rc = SCA_APPEARANCE_ERR_NOT_IN_USE;
|
|
goto done;
|
|
}
|
|
|
|
app = sca_appearance_list_unlink_index( app_list, idx );
|
|
if ( app == NULL ) {
|
|
LM_ERR( "Failed to unlink %.*s appearance-index %d: invalid index",
|
|
STR_FMT( aor ), idx );
|
|
rc = SCA_APPEARANCE_ERR_INDEX_INVALID;
|
|
goto done;
|
|
}
|
|
sca_appearance_free( app );
|
|
|
|
rc = SCA_APPEARANCE_OK;
|
|
|
|
done:
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
|
|
return( rc );
|
|
}
|
|
|
|
int
|
|
sca_appearance_owner_release_all( str *aor, str *owner )
|
|
{
|
|
sca_appearance_list *app_list = NULL;
|
|
sca_appearance *app, **cur_app, **tmp_app;
|
|
sca_hash_slot *slot;
|
|
sca_hash_entry *ent;
|
|
int slot_idx = -1;
|
|
int released = -1;
|
|
|
|
slot_idx = sca_uri_lock_shared_appearance( sca, aor );
|
|
slot = sca_hash_table_slot_for_index( sca->appearances, slot_idx );
|
|
|
|
for ( ent = slot->entries; ent != NULL; ent = ent->next ) {
|
|
if ( ent->compare( aor, ent->value ) == 0 ) {
|
|
app_list = (sca_appearance_list *)ent->value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
released = 0;
|
|
|
|
if ( app_list == NULL ) {
|
|
LM_DBG( "sca_appearance_owner_release_all: No appearances for %.*s",
|
|
STR_FMT( aor ));
|
|
goto done;
|
|
}
|
|
|
|
for ( cur_app = &app_list->appearances; *cur_app != NULL;
|
|
cur_app = tmp_app ) {
|
|
tmp_app = &(*cur_app)->next;
|
|
|
|
if ( !SCA_STR_EQ( owner, &(*cur_app)->owner )) {
|
|
continue;
|
|
}
|
|
|
|
app = *cur_app;
|
|
*cur_app = (*cur_app)->next;
|
|
tmp_app = cur_app;
|
|
|
|
if ( app ) {
|
|
sca_appearance_free( app );
|
|
released++;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if ( slot_idx >= 0 ) {
|
|
sca_hash_table_unlock_index( sca->appearances, slot_idx );
|
|
}
|
|
|
|
return( released );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_for_index_unsafe( sca_mod *scam, str *aor, int app_idx,
|
|
int slot_idx )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app = NULL;
|
|
sca_hash_slot *slot;
|
|
sca_hash_entry *ent;
|
|
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
app_list = NULL;
|
|
for ( ent = slot->entries; ent != NULL; ent = ent->next ) {
|
|
if ( ent->compare( aor, ent->value ) == 0 ) {
|
|
app_list = (sca_appearance_list *)ent->value;
|
|
break;
|
|
}
|
|
}
|
|
if ( app_list == NULL ) {
|
|
LM_ERR( "No appearances for %.*s", STR_FMT( aor ));
|
|
return( NULL );
|
|
}
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
if ( app->index == app_idx ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( app );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_for_dialog_unsafe( sca_mod *scam, str *aor, sca_dialog *dialog,
|
|
int slot_idx )
|
|
{
|
|
sca_appearance_list *app_list;
|
|
sca_appearance *app = NULL;
|
|
sca_hash_slot *slot;
|
|
sca_hash_entry *ent;
|
|
|
|
slot = sca_hash_table_slot_for_index( scam->appearances, slot_idx );
|
|
|
|
app_list = NULL;
|
|
for ( ent = slot->entries; ent != NULL; ent = ent->next ) {
|
|
if ( ent->compare( aor, ent->value ) == 0 ) {
|
|
app_list = (sca_appearance_list *)ent->value;
|
|
break;
|
|
}
|
|
}
|
|
if ( app_list == NULL ) {
|
|
LM_ERR( "No appearances for %.*s", STR_FMT( aor ));
|
|
return( NULL );
|
|
}
|
|
|
|
for ( app = app_list->appearances; app != NULL; app = app->next ) {
|
|
if ( SCA_STR_EQ( &app->dialog.call_id, &dialog->call_id ) &&
|
|
SCA_STR_EQ( &app->dialog.from_tag, &dialog->from_tag )) {
|
|
#ifdef notdef
|
|
if ( !SCA_STR_EMPTY( &app->dialog.to_tag ) &&
|
|
!SCA_STR_EMPTY( &dialog->to_tag ) &&
|
|
!SCA_STR_EQ( &app->dialog.to_tag, &dialog->to_tag )) {
|
|
continue;
|
|
}
|
|
#endif /* notdef */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( app );
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_for_tags_unsafe( sca_mod *scam, str *aor,
|
|
str *call_id, str *from_tag, str *to_tag, int slot_idx )
|
|
{
|
|
sca_dialog dialog;
|
|
char dlg_buf[ 1024 ];
|
|
|
|
dialog.id.s = dlg_buf;
|
|
if ( sca_dialog_build_from_tags( &dialog, sizeof( dlg_buf ),
|
|
call_id, from_tag, to_tag ) < 0 ) {
|
|
LM_ERR( "sca_appearance_for_tags_unsafe: failed to build dialog "
|
|
"from tags" );
|
|
return( NULL );
|
|
}
|
|
|
|
return( sca_appearance_for_dialog_unsafe( scam, aor, &dialog, slot_idx ));
|
|
}
|
|
|
|
sca_appearance *
|
|
sca_appearance_unlink_by_tags( sca_mod *scam, str *aor,
|
|
str *call_id, str *from_tag, str *to_tag )
|
|
{
|
|
sca_appearance *app = NULL, *unl_app;
|
|
int slot_idx = -1;
|
|
|
|
slot_idx = sca_hash_table_index_for_key( scam->appearances, aor );
|
|
sca_hash_table_lock_index( scam->appearances, slot_idx );
|
|
|
|
app = sca_appearance_for_tags_unsafe( scam, aor, call_id, from_tag,
|
|
to_tag, slot_idx );
|
|
if ( app == NULL ) {
|
|
LM_ERR( "sca_appearance_unlink_by_tags: no appearances found for %.*s "
|
|
"with dialog %.*s;%.*s;%.*s", STR_FMT( aor ),
|
|
STR_FMT( call_id ), STR_FMT( from_tag ), STR_FMT( to_tag ));
|
|
goto done;
|
|
}
|
|
|
|
unl_app = sca_appearance_list_unlink_index( app->appearance_list,
|
|
app->index );
|
|
if ( unl_app == NULL || unl_app != app ) {
|
|
LM_ERR( "sca_appearance_unlink_by_tags: failed to unlink %.*s "
|
|
"appearance-index %d", STR_FMT( aor ), app->index );
|
|
app = NULL;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if ( slot_idx >= 0 ) {
|
|
sca_hash_table_unlock_index( scam->appearances, slot_idx );
|
|
}
|
|
|
|
return( app );
|
|
}
|
|
|
|
void
|
|
sca_appearance_purge_stale( unsigned int ticks, void *param )
|
|
{
|
|
struct notify_list {
|
|
struct notify_list *next;
|
|
str aor;
|
|
};
|
|
|
|
sca_mod *scam = (sca_mod *)param;
|
|
sca_hash_table *ht;
|
|
sca_hash_entry *ent;
|
|
sca_appearance_list *app_list;
|
|
sca_appearance **cur_app, **tmp_app, *app = NULL;
|
|
struct notify_list *notify_list = NULL, *tmp_nl;
|
|
int i;
|
|
int unlinked;
|
|
time_t now, ttl;
|
|
|
|
LM_INFO( "SCA: purging stale appearances" );
|
|
|
|
assert( scam != NULL );
|
|
assert( scam->appearances != NULL );
|
|
|
|
now = time( NULL );
|
|
|
|
ht = scam->appearances;
|
|
for ( i = 0; i < ht->size; i++ ) {
|
|
sca_hash_table_lock_index( ht, i );
|
|
|
|
for ( ent = ht->slots[ i ].entries; ent != NULL; ent = ent->next ) {
|
|
app_list = (sca_appearance_list *)ent->value;
|
|
if ( app_list == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
unlinked = 0;
|
|
|
|
for ( cur_app = &app_list->appearances; *cur_app != NULL;
|
|
cur_app = tmp_app ) {
|
|
tmp_app = &(*cur_app)->next;
|
|
|
|
switch ((*cur_app)->state ) {
|
|
case SCA_APPEARANCE_STATE_ACTIVE_PENDING:
|
|
ttl = SCA_APPEARANCE_STATE_PENDING_TTL;
|
|
break;
|
|
|
|
case SCA_APPEARANCE_STATE_SEIZED:
|
|
ttl = SCA_APPEARANCE_STATE_SEIZED_TTL;
|
|
break;
|
|
|
|
default:
|
|
/* XXX for now just skip other appearances */
|
|
ttl = now + 60;
|
|
break;
|
|
}
|
|
if (( now - (*cur_app)->times.mtime ) < ttl ) {
|
|
continue;
|
|
}
|
|
|
|
/* unlink stale appearance */
|
|
app = *cur_app;
|
|
*cur_app = (*cur_app)->next;
|
|
tmp_app = cur_app;
|
|
|
|
if ( app ) {
|
|
sca_appearance_free( app );
|
|
}
|
|
|
|
if ( unlinked ) {
|
|
/* we've already added this AoR to the NOTIFY list */
|
|
continue;
|
|
}
|
|
unlinked++;
|
|
|
|
/*
|
|
* can't notify while slot is locked. make a list of AoRs to
|
|
* notify after unlocking.
|
|
*/
|
|
tmp_nl = (struct notify_list *)pkg_malloc(
|
|
sizeof( struct notify_list ));
|
|
if ( tmp_nl == NULL ) {
|
|
LM_ERR( "sca_appearance_purge_stale: failed to pkg_malloc "
|
|
"notify list entry for %.*s",
|
|
STR_FMT( &app_list->aor ));
|
|
continue;
|
|
}
|
|
|
|
tmp_nl->aor.s = (char *)pkg_malloc( app_list->aor.len );
|
|
if ( tmp_nl->aor.s == NULL ) {
|
|
LM_ERR( "sca_appearance_purge_stale: failed to pkg_malloc "
|
|
"space for copy of %.*s",
|
|
STR_FMT( &app_list->aor ));
|
|
pkg_free( tmp_nl );
|
|
continue;
|
|
}
|
|
SCA_STR_COPY( &tmp_nl->aor, &app_list->aor );
|
|
|
|
/* simple insert-at-head. order doesn't matter. */
|
|
tmp_nl->next = notify_list;
|
|
notify_list = tmp_nl;
|
|
}
|
|
}
|
|
|
|
sca_hash_table_unlock_index( ht, i );
|
|
|
|
for ( ; notify_list != NULL; notify_list = tmp_nl ) {
|
|
tmp_nl = notify_list->next;
|
|
|
|
LM_INFO( "sca_appearance_purge_stale: notifying %.*s call-info "
|
|
"subscribers", STR_FMT( ¬ify_list->aor ));
|
|
|
|
if ( sca_notify_call_info_subscribers( scam,
|
|
¬ify_list->aor ) < 0 ) {
|
|
LM_ERR( "sca_appearance_purge_stale: failed to send "
|
|
"call-info NOTIFY %.*s subscribers",
|
|
STR_FMT( ¬ify_list->aor ));
|
|
/* fall through, free memory anyway */
|
|
}
|
|
|
|
if ( notify_list->aor.s ) {
|
|
pkg_free( notify_list->aor.s );
|
|
}
|
|
pkg_free( notify_list );
|
|
}
|
|
}
|
|
}
|