1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360 |
- /*
- * Copyright (C) 2008 Voice System SRL
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- /*!
- * \file
- * \brief Profile related functions for the dialog module
- * \ingroup dialog
- * Module: \ref dialog
- */
- #include "../../mem/shm_mem.h"
- #include "../../hashes.h"
- #include "../../trim.h"
- #include "../../dprint.h"
- #include "../../ut.h"
- #include "../../route.h"
- #include "../../modules/tm/tm_load.h"
- #include "../../lib/srutils/sruid.h"
- #include "dlg_hash.h"
- #include "dlg_var.h"
- #include "dlg_handlers.h"
- #include "dlg_profile.h"
- /*! size of dialog profile hash */
- #define PROFILE_HASH_SIZE 16
- /*! tm bindings */
- extern struct tm_binds d_tmb;
- /*! global dialog message id */
- static unsigned int current_dlg_msg_id = 0 ;
- static unsigned int current_dlg_msg_pid = 0 ;
- /*! pending dialog links */
- static dlg_profile_link_t *current_pending_linkers = NULL;
- /*! global dialog profile list */
- static dlg_profile_table_t *profiles = NULL;
- static dlg_profile_table_t* new_dlg_profile( str *name,
- unsigned int size, unsigned int has_value);
- extern int update_dlg_timeout(dlg_cell_t *, int);
- static sruid_t _dlg_profile_sruid;
- /*!
- * \brief Add profile definitions to the global list
- * \see new_dlg_profile
- * \param profiles profile name
- * \param has_value set to 0 for a profile without value, otherwise it has a value
- * \return 0 on success, -1 on failure
- */
- int add_profile_definitions( char* profiles, unsigned int has_value)
- {
- char *p;
- char *d;
- str name;
- unsigned int i;
- if (profiles==NULL || strlen(profiles)==0 )
- return 0;
- p = profiles;
- do {
- /* locate name of profile */
- name.s = p;
- d = strchr( p, ';');
- if (d) {
- name.len = d-p;
- d++;
- } else {
- name.len = strlen(p);
- }
- /* we have the name -> trim it for spaces */
- trim_spaces_lr( name );
- /* check len name */
- if (name.len==0)
- /* ignore */
- continue;
- /* check the name format */
- for(i=0;i<name.len;i++) {
- if ( !isalnum(name.s[i]) && name.s[i] != '_' ) {
- LM_ERR("bad profile name <%.*s>, char %c - use only "
- "alphanumerical characters or '_'\n", name.len,name.s,name.s[i]);
- return -1;
- }
- }
- /* name ok -> create the profile */
- LM_DBG("creating profile <%.*s>\n",name.len,name.s);
- if (new_dlg_profile( &name, PROFILE_HASH_SIZE, has_value)==NULL) {
- LM_ERR("failed to create new profile <%.*s>\n",name.len,name.s);
- return -1;
- }
- }while( (p=d)!=NULL );
- return 0;
- }
- /*!
- * \brief Search a dialog profile in the global list
- * \note Linear search, this won't have the best performance for huge profile lists
- * \param name searched dialog profile
- * \return pointer to the profile on success, NULL otherwise
- */
- struct dlg_profile_table* search_dlg_profile(str *name)
- {
- struct dlg_profile_table *profile;
- for( profile=profiles ; profile ; profile=profile->next ) {
- if (name->len==profile->name.len &&
- memcmp(name->s,profile->name.s,name->len)==0 )
- return profile;
- }
- return NULL;
- }
- /*!
- * \brief Creates a new dialog profile
- * \see add_profile_definitions
- * \param name profile name
- * \param size profile size
- * \param has_value set to 0 for a profile without value, otherwise it has a value
- * \return pointer to the created dialog on success, NULL otherwise
- */
- static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size,
- unsigned int has_value)
- {
- struct dlg_profile_table *profile;
- struct dlg_profile_table *ptmp;
- unsigned int len;
- unsigned int i;
- if ( name->s==NULL || name->len==0 || size==0 ) {
- LM_ERR("invalid parameters\n");
- return NULL;
- }
- for( len=0,i=0 ; i<8*sizeof(size) ; i++ ) {
- if ( size & (1<<i) ) len++;
- }
- if (len!=1) {
- LM_ERR(" size %u is not power of 2!\n", size);
- return NULL;
- }
- profile = search_dlg_profile(name);
- if (profile!=NULL) {
- LM_ERR("duplicate dialog profile registered <%.*s>\n",
- name->len, name->s);
- return NULL;
- }
- len = sizeof(struct dlg_profile_table) +
- size*sizeof(struct dlg_profile_entry) +
- name->len + 1;
- profile = (struct dlg_profile_table *)shm_malloc(len);
- if (profile==NULL) {
- LM_ERR("no more shm mem\n");
- return NULL;
- }
- memset( profile , 0 , len);
- profile->size = size;
- profile->has_value = (has_value==0)?0:1;
- /* init lock */
- if (lock_init( &profile->lock )==NULL) {
- LM_ERR("failed to init lock\n");
- shm_free(profile);
- return NULL;
- }
- /* set inner pointers */
- profile->entries = (struct dlg_profile_entry*)(profile + 1);
- profile->name.s = ((char*)profile->entries) +
- size*sizeof(struct dlg_profile_entry);
- /* copy the name of the profile */
- memcpy( profile->name.s, name->s, name->len );
- profile->name.len = name->len;
- profile->name.s[profile->name.len] = 0;
- /* link profile */
- for( ptmp=profiles ; ptmp && ptmp->next; ptmp=ptmp->next );
- if (ptmp==NULL) {
- profiles = profile;
- sruid_init(&_dlg_profile_sruid, '-', "dlgp", SRUID_INC);
- } else {
- ptmp->next = profile;
- }
- return profile;
- }
- /*!
- * \brief Destroy a dialog profile list
- * \param profile dialog profile
- */
- static void destroy_dlg_profile(struct dlg_profile_table *profile)
- {
- if (profile==NULL)
- return;
- lock_destroy( &profile->lock );
- shm_free( profile );
- return;
- }
- /*!
- * \brief Destroy the global dialog profile list
- */
- void destroy_dlg_profiles(void)
- {
- struct dlg_profile_table *profile;
- while(profiles) {
- profile = profiles;
- profiles = profiles->next;
- destroy_dlg_profile( profile );
- }
- return;
- }
- /*!
- * \brief Destroy dialog linkers
- * \param linker dialog linker
- */
- void destroy_linkers(struct dlg_profile_link *linker)
- {
- struct dlg_profile_entry *p_entry;
- struct dlg_profile_link *l;
- struct dlg_profile_hash *lh;
- while(linker) {
- l = linker;
- linker = linker->next;
- /* unlink from profile table */
- if (l->hash_linker.next) {
- p_entry = &l->profile->entries[l->hash_linker.hash];
- lock_get( &l->profile->lock );
- lh = &l->hash_linker;
- /* last element on the list? */
- if (lh==lh->next) {
- p_entry->first = NULL;
- } else {
- if (p_entry->first==lh)
- p_entry->first = lh->next;
- lh->next->prev = lh->prev;
- lh->prev->next = lh->next;
- }
- lh->next = lh->prev = NULL;
- p_entry->content --;
- lock_release( &l->profile->lock );
- }
- /* free memory */
- shm_free(l);
- }
- }
- /*!
- * \brief Calculate the hash profile from a dialog
- * \see core_hash
- * \param value hash source
- * \param dlg dialog cell
- * \param profile dialog profile table (for hash size)
- * \return value hash if the value has a value, hash over dialog otherwise
- */
- inline static unsigned int calc_hash_profile(str *value1, str *value2,
- dlg_profile_table_t *profile)
- {
- if (profile->has_value) {
- /* do hash over the value1 */
- return core_hash( value1, NULL, profile->size);
- } else {
- /* do hash over the value2 */
- if(value2)
- return core_hash( value2, NULL, profile->size);
- return 0;
- }
- }
- /*!
- * \brief Remove remote profile items that are expired
- * \param te expiration time
- */
- void remove_expired_remote_profiles(time_t te)
- {
- struct dlg_profile_table *profile;
- struct dlg_profile_entry *p_entry;
- struct dlg_profile_hash *lh;
- struct dlg_profile_hash *kh;
- int i;
- for( profile=profiles ; profile ; profile=profile->next ) {
- if(profile->flags&FLAG_PROFILE_REMOTE) {
- for(i=0; i<profile->size; i++) {
- /* space for optimization */
- lock_get(&profile->lock);
- p_entry = &profile->entries[i];
- lh = p_entry->first;
- while(lh) {
- kh = lh->next;
- if(lh->dlg==NULL && lh->expires>0 && lh->expires<te) {
- /* last element on the list? */
- if (lh==lh->next) {
- p_entry->first = NULL;
- } else {
- if (p_entry->first==lh)
- p_entry->first = lh->next;
- lh->next->prev = lh->prev;
- lh->prev->next = lh->next;
- }
- lh->next = lh->prev = NULL;
- if(lh->linker) shm_free(lh->linker);
- p_entry->content--;
- lock_release(&profile->lock);
- return;
- }
- lh = kh;
- }
- lock_release(&profile->lock);
- }
- }
- }
- }
- /*!
- * \brief Remove profile
- * \param profile pointer to profile
- * \param value profile value
- * \param puid profile unique id
- */
- int remove_profile(dlg_profile_table_t *profile, str *value, str *puid)
- {
- unsigned int hash;
- struct dlg_profile_entry *p_entry;
- struct dlg_profile_hash *lh;
- hash = calc_hash_profile(value, puid, profile);
- lock_get(&profile->lock );
- p_entry = &profile->entries[hash];
- lh = p_entry->first;
- if(lh) {
- do {
- if(lh->dlg==NULL && lh->puid_len==puid->len
- && lh->value.len==value->len
- && strncmp(lh->puid, puid->s, puid->len)==0
- && strncmp(lh->value.s, value->s, value->len)==0) {
- /* last element on the list? */
- if (lh==lh->next) {
- p_entry->first = NULL;
- } else {
- if (p_entry->first==lh)
- p_entry->first = lh->next;
- lh->next->prev = lh->prev;
- lh->prev->next = lh->next;
- }
- lh->next = lh->prev = NULL;
- if(lh->linker) shm_free(lh->linker);
- p_entry->content--;
- return 1;
- }
- lh = lh->next;
- } while(lh != p_entry->first);
- }
- lock_release(&profile->lock );
- return 0;
- }
- /*!
- * \brief Callback for cleanup of profile local vars
- * \param msg SIP message
- * \param flags unused
- * \param param unused
- * \return 1
- */
- int cb_profile_reset( struct sip_msg *msg, unsigned int flags, void *param )
- {
- current_dlg_msg_id = 0;
- current_dlg_msg_pid = 0;
- if (current_pending_linkers) {
- destroy_linkers(current_pending_linkers);
- current_pending_linkers = NULL;
- }
- /* need to return non-zero - 0 will break the exec of the request */
- return 1;
- }
- /*!
- * \brief Cleanup a profile
- * \param msg SIP message
- * \param flags unused
- * \param param unused
- * \return 1
- */
- int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
- {
- dlg_cell_t *dlg;
- current_dlg_msg_id = 0;
- current_dlg_msg_pid = 0;
- dlg = dlg_get_ctx_dialog();
- if (dlg!=NULL) {
- if(dlg->dflags & DLG_FLAG_TM) {
- dlg_unref(dlg, 1);
- } else {
- /* dialog didn't make it to tm */
- dlg_unref(dlg, 2);
- }
- }
- if (current_pending_linkers) {
- destroy_linkers(current_pending_linkers);
- current_pending_linkers = NULL;
- }
- /* need to return non-zero - 0 will break the exec of the request */
- return 1;
- }
- /*!
- * \brief Link a dialog profile
- * \param linker dialog linker
- * \param vkey key for profile hash table
- */
- static void link_profile(struct dlg_profile_link *linker, str *vkey)
- {
- unsigned int hash;
- struct dlg_profile_entry *p_entry;
- /* calculate the hash position */
- hash = calc_hash_profile(&linker->hash_linker.value, vkey, linker->profile);
- linker->hash_linker.hash = hash;
- /* insert into profile hash table */
- p_entry = &linker->profile->entries[hash];
- lock_get( &linker->profile->lock );
- if (p_entry->first) {
- linker->hash_linker.prev = p_entry->first->prev;
- linker->hash_linker.next = p_entry->first;
- p_entry->first->prev->next = &linker->hash_linker;
- p_entry->first->prev = &linker->hash_linker;
- } else {
- p_entry->first = linker->hash_linker.next
- = linker->hash_linker.prev = &linker->hash_linker;
- }
- p_entry->content ++;
- lock_release( &linker->profile->lock );
- }
- /*!
- * \brief Link a dialog profile
- * \param linker dialog linker
- * \param dlg dialog cell
- */
- static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
- {
- struct dlg_entry *d_entry;
- /* add the linker to the dialog */
- /* FIXME zero h_id is not 100% for testing if the dialog is inserted
- * into the hash table -> we need circular lists -bogdan */
- if (dlg->h_id) {
- d_entry = &d_table->entries[dlg->h_entry];
- dlg_lock( d_table, d_entry);
- linker->next = dlg->profile_links;
- dlg->profile_links =linker;
- linker->hash_linker.dlg = dlg;
- dlg_unlock( d_table, d_entry);
- } else {
- linker->next = dlg->profile_links;
- dlg->profile_links =linker;
- linker->hash_linker.dlg = dlg;
- }
- link_profile(linker, &dlg->callid);
- }
- /*!
- * \brief Set the global variables to the current dialog
- * \param msg SIP message
- * \param dlg dialog cell
- */
- void set_current_dialog(sip_msg_t *msg, dlg_cell_t *dlg)
- {
- struct dlg_profile_link *linker;
- struct dlg_profile_link *tlinker;
- LM_DBG("setting current dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
- /* if linkers are not from current request, just discard them */
- if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
- current_dlg_msg_id = msg->id;
- current_dlg_msg_pid = msg->pid;
- destroy_linkers(current_pending_linkers);
- } else {
- /* add the linker, one by one, to the dialog */
- linker = current_pending_linkers;
- while (linker) {
- tlinker = linker;
- linker = linker->next;
- /* process tlinker */
- tlinker->next = NULL;
- link_dlg_profile( tlinker, dlg);
- }
- }
- current_pending_linkers = NULL;
- }
- /*!
- * \brief Set a dialog profile
- * \param msg SIP message
- * \param value value
- * \param profile dialog profile table
- * \return 0 on success, -1 on failure
- */
- int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
- {
- dlg_cell_t *dlg = NULL;
- dlg_profile_link_t *linker;
- /* get current dialog */
- dlg = dlg_get_msg_dialog(msg);
- if (dlg==NULL && !is_route_type(REQUEST_ROUTE)) {
- LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
- REQUEST_ROUTE);
- return -1;
- }
- /* build new linker */
- linker = (struct dlg_profile_link*)shm_malloc(
- sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
- if (linker==NULL) {
- LM_ERR("no more shm memory\n");
- goto error;
- }
- memset(linker, 0, sizeof(struct dlg_profile_link));
- /* set backpointers to profile and linker (itself) */
- linker->profile = profile;
- linker->hash_linker.linker = linker;
- /* set the value */
- if (profile->has_value) {
- linker->hash_linker.value.s = (char*)(linker+1);
- memcpy( linker->hash_linker.value.s, value->s, value->len);
- linker->hash_linker.value.len = value->len;
- }
- sruid_next_safe(&_dlg_profile_sruid);
- strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
- linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;
- if (dlg!=NULL) {
- /* add linker directly to the dialog and profile */
- link_dlg_profile( linker, dlg);
- } else {
- /* if existing linkers are not from current request, just discard them */
- if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
- current_dlg_msg_id = msg->id;
- current_dlg_msg_pid = msg->pid;
- destroy_linkers(current_pending_linkers);
- current_pending_linkers = NULL;
- }
- /* no dialog yet -> set linker as pending */
- if (msg->id!=current_dlg_msg_id || msg->pid!=current_dlg_msg_pid) {
- current_dlg_msg_id = msg->id;
- current_dlg_msg_pid = msg->pid;
- destroy_linkers(current_pending_linkers);
- }
- linker->next = current_pending_linkers;
- current_pending_linkers = linker;
- }
- dlg_release(dlg);
- return 0;
- error:
- dlg_release(dlg);
- return -1;
- }
- /*!
- * \brief Add dialog to a profile
- * \param dlg dialog
- * \param value value
- * \param profile dialog profile table
- * \return 0 on success, -1 on failure
- */
- int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profile,
- str *puid, time_t expires, int flags)
- {
- dlg_profile_link_t *linker;
- str vkey;
- /* build new linker */
- linker = (struct dlg_profile_link*)shm_malloc(
- sizeof(struct dlg_profile_link) + (profile->has_value?(value->len+1):0) );
- if (linker==NULL) {
- LM_ERR("no more shm memory\n");
- goto error;
- }
- memset(linker, 0, sizeof(struct dlg_profile_link));
- /* set backpointers to profile and linker (itself) */
- linker->profile = profile;
- linker->hash_linker.linker = linker;
- /* set the value */
- if (profile->has_value) {
- linker->hash_linker.value.s = (char*)(linker+1);
- memcpy( linker->hash_linker.value.s, value->s, value->len);
- linker->hash_linker.value.len = value->len;
- linker->hash_linker.value.s[value->len] = '\0';
- }
- if(puid && puid->s && puid->len>0 && puid->len<SRUID_SIZE) {
- strcpy(linker->hash_linker.puid, puid->s);
- linker->hash_linker.puid_len = puid->len;
- } else {
- sruid_next_safe(&_dlg_profile_sruid);
- strcpy(linker->hash_linker.puid, _dlg_profile_sruid.uid.s);
- linker->hash_linker.puid_len = _dlg_profile_sruid.uid.len;
- }
- linker->hash_linker.expires = expires;
- linker->hash_linker.flags = flags;
- /* add linker directly to the dialog and profile */
- if(dlg!=NULL) {
- link_dlg_profile(linker, dlg);
- } else {
- vkey.s = linker->hash_linker.puid;
- vkey.len = linker->hash_linker.puid_len;
- profile->flags |= FLAG_PROFILE_REMOTE;
- link_profile(linker, &vkey);
- }
- return 0;
- error:
- return -1;
- }
- /*!
- * \brief Unset a dialog profile
- * \param msg SIP message
- * \param value value
- * \param profile dialog profile table
- * \return 1 on success, -1 on failure
- */
- int unset_dlg_profile(sip_msg_t *msg, str *value,
- dlg_profile_table_t *profile)
- {
- dlg_cell_t *dlg;
- dlg_profile_link_t *linker;
- dlg_profile_link_t *linker_prev;
- dlg_entry_t *d_entry;
- if (is_route_type(REQUEST_ROUTE)) {
- LM_ERR("dialog delete profile cannot be used in request route\n");
- return -1;
- }
- /* get current dialog */
- dlg = dlg_get_msg_dialog(msg);
- if (dlg==NULL) {
- LM_WARN("dialog is NULL for delete profile\n");
- return -1;
- }
- /* check the dialog linkers */
- d_entry = &d_table->entries[dlg->h_entry];
- dlg_lock( d_table, d_entry);
- linker = dlg->profile_links;
- linker_prev = NULL;
- for( ; linker ; linker_prev=linker,linker=linker->next) {
- if (linker->profile==profile) {
- if (profile->has_value==0) {
- goto found;
- } else if (value && value->len==linker->hash_linker.value.len &&
- memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
- goto found;
- }
- /* allow further search - maybe the dialog is inserted twice in
- * the same profile, but with different values -bogdan
- */
- }
- }
- dlg_unlock( d_table, d_entry);
- dlg_release(dlg);
- return -1;
- found:
- /* table still locked */
- /* remove the linker element from dialog */
- if (linker_prev==NULL) {
- dlg->profile_links = linker->next;
- } else {
- linker_prev->next = linker->next;
- }
- linker->next = NULL;
- dlg_unlock( d_table, d_entry);
- /* remove linker from profile table and free it */
- destroy_linkers(linker);
- dlg_release(dlg);
- return 1;
- }
- /*!
- * \brief Check if a dialog belongs to a profile
- * \param msg SIP message
- * \param profile dialog profile table
- * \param value value
- * \return 1 on success, -1 on failure
- */
- int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
- str *value)
- {
- struct dlg_cell *dlg;
- struct dlg_profile_link *linker;
- struct dlg_entry *d_entry;
- int ret;
- /* get current dialog */
- dlg = dlg_get_msg_dialog(msg);
- if (dlg==NULL)
- return -1;
- ret = -1;
- /* check the dialog linkers */
- d_entry = &d_table->entries[dlg->h_entry];
- dlg_lock( d_table, d_entry);
- for( linker=dlg->profile_links ; linker ; linker=linker->next) {
- if (linker->profile==profile) {
- if (profile->has_value==0) {
- dlg_unlock( d_table, d_entry);
- ret = 1;
- goto done;
- } else if (value && value->len==linker->hash_linker.value.len &&
- memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
- dlg_unlock( d_table, d_entry);
- ret = 1;
- goto done;
- }
- /* allow further search - maybe the dialog is inserted twice in
- * the same profile, but with different values -bogdan
- */
- }
- }
- dlg_unlock( d_table, d_entry);
- done:
- dlg_release(dlg);
- return ret;
- }
- /*!
- * \brief Get the size of a profile
- * \param profile evaluated profile
- * \param value value
- * \return the profile size
- */
- unsigned int get_profile_size(struct dlg_profile_table *profile, str *value)
- {
- unsigned int n,i;
- struct dlg_profile_hash *ph;
- if (profile->has_value==0 || value==NULL) {
- /* iterate through the hash and count all records */
- lock_get( &profile->lock );
- for( i=0,n=0 ; i<profile->size ; i++ )
- n += profile->entries[i].content;
- lock_release( &profile->lock );
- return n;
- } else {
- /* iterate through the hash entry and count only matching */
- /* calculate the hash position */
- i = calc_hash_profile( value, NULL, profile);
- n = 0;
- lock_get( &profile->lock );
- ph = profile->entries[i].first;
- if(ph) {
- do {
- /* compare */
- if ( value->len==ph->value.len &&
- memcmp(value->s,ph->value.s,value->len)==0 ) {
- /* found */
- n++;
- }
- /* next */
- ph=ph->next;
- }while( ph!=profile->entries[i].first );
- }
- lock_release( &profile->lock );
- return n;
- }
- }
- /*
- * Determine if message is in a dialog currently being tracked
- */
- int is_known_dlg(struct sip_msg *msg) {
- dlg_cell_t *dlg;
- dlg = dlg_get_msg_dialog(msg);
-
- if(dlg == NULL)
- return -1;
- dlg_release(dlg);
- return 1;
- }
- /*
- * \brief Set the timeout of all the dialogs in a given profile, by value.
- * \param profile The evaluated profile name.
- * \param value The value constraint.
- * \param timeout The dialog timeout to apply.
- */
- int dlg_set_timeout_by_profile(struct dlg_profile_table *profile,
- str *value, int timeout)
- {
- unsigned int i = 0;
- dlg_cell_t *this_dlg = NULL;
- struct dlg_profile_hash *ph = NULL;
- /* Private structure necessary for manipulating dialog
- * timeouts outside of profile locks. Admittedly, an
- * ugly hack, but avoids some concurrency issues.
- */
- struct dlg_map_list {
- unsigned int h_id;
- unsigned int h_entry;
- struct dlg_map_list *next;
- } *map_head, *map_scan, *map_scan_next;
- map_head = NULL;
- /* If the profile has no value, iterate through every
- * node and set its timeout.
- */
- if(profile->has_value == 0 || value == NULL) {
- lock_get(&profile->lock);
- for(i = 0; i < profile->size; i ++) {
- ph = profile->entries[i].first;
- if(!ph) continue;
-
- do {
- struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));
- if(!d)
- return -1;
- memset(d, 0, sizeof(struct dlg_map_list));
- d->h_id = ph->dlg->h_id;
- d->h_entry = ph->dlg->h_entry;
- if(map_head == NULL)
- map_head = d;
- else {
- d->next = map_head;
- map_head = d;
- }
-
- ph = ph->next;
- } while(ph != profile->entries[i].first);
- }
- lock_release(&profile->lock);
- }
- else {
- i = calc_hash_profile(value, NULL, profile);
- lock_get(&profile->lock);
- ph = profile->entries[i].first;
- if(ph) {
- do {
- if(ph && value->len == ph->value.len &&
- memcmp(value->s, ph->value.s, value->len) == 0) {
- struct dlg_map_list *d = malloc(sizeof(struct dlg_map_list));
- if(!d)
- return -1;
- memset(d, 0, sizeof(struct dlg_map_list));
- d->h_id = ph->dlg->h_id;
- d->h_entry = ph->dlg->h_entry;
- if(map_head == NULL)
- map_head = d;
- else {
- d->next = map_head;
- map_head = d;
- }
- }
- ph = ph->next;
- } while(ph && ph != profile->entries[i].first);
- }
- lock_release(&profile->lock);
- }
- /* Walk the list and bulk-set the timeout */
-
- for(map_scan = map_head; map_scan != NULL; map_scan = map_scan_next) {
- map_scan_next = map_scan->next;
- this_dlg = dlg_lookup(map_scan->h_entry, map_scan->h_id);
- if(!this_dlg) {
- LM_CRIT("Unable to find dialog %d:%d\n", map_scan->h_entry, map_scan->h_id);
- } else if(this_dlg->state >= DLG_STATE_EARLY) {
- if(update_dlg_timeout(this_dlg, timeout) < 0) {
- LM_ERR("Unable to set timeout on %d:%d\n", map_scan->h_entry,
- map_scan->h_id);
- }
- dlg_release(this_dlg);
- }
- free(map_scan);
- }
- return 0;
- }
- /****************************** MI commands *********************************/
- /*!
- * \brief Output a profile via MI interface
- * \param cmd_tree MI command tree
- * \param param unused
- * \return MI root output on success, NULL on failure
- */
- struct mi_root * mi_get_profile(struct mi_root *cmd_tree, void *param)
- {
- struct mi_node* node;
- struct mi_root* rpl_tree= NULL;
- struct mi_node* rpl = NULL;
- struct mi_attr* attr;
- struct dlg_profile_table *profile;
- str *value;
- str *profile_name;
- unsigned int size;
- int len;
- char *p;
- node = cmd_tree->node.kids;
- if (node==NULL || !node->value.s || !node->value.len)
- return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
- profile_name = &node->value;
- if (node->next) {
- node = node->next;
- if (!node->value.s || !node->value.len)
- return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
- if (node->next)
- return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
- value = &node->value;
- } else {
- value = NULL;
- }
- /* search for the profile */
- profile = search_dlg_profile( profile_name );
- if (profile==NULL)
- return init_mi_tree( 404, MI_SSTR("Profile not found"));
- size = get_profile_size( profile , value );
- rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
- if (rpl_tree==0)
- return 0;
- rpl = &rpl_tree->node;
- node = add_mi_node_child(rpl, MI_DUP_VALUE, "profile", 7, NULL, 0);
- if (node==0) {
- free_mi_tree(rpl_tree);
- return NULL;
- }
- attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4,
- profile->name.s, profile->name.len);
- if(attr == NULL) {
- goto error;
- }
- if (value) {
- attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, value->s, value->len);
- } else {
- attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, NULL, 0);
- }
- if(attr == NULL) {
- goto error;
- }
- p= int2str((unsigned long)size, &len);
- attr = add_mi_attr(node, MI_DUP_VALUE, "count", 5, p, len);
- if(attr == NULL) {
- goto error;
- }
- return rpl_tree;
- error:
- free_mi_tree(rpl_tree);
- return NULL;
- }
- /*!
- * \brief List the profiles via MI interface
- * \param cmd_tree MI command tree
- * \param param unused
- * \return MI root output on success, NULL on failure
- */
- struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param )
- {
- struct mi_node* node;
- struct mi_root* rpl_tree= NULL;
- struct mi_node* rpl = NULL;
- struct dlg_profile_table *profile;
- struct dlg_profile_hash *ph;
- str *profile_name;
- str *value;
- unsigned int i;
- node = cmd_tree->node.kids;
- if (node==NULL || !node->value.s || !node->value.len)
- return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
- profile_name = &node->value;
- if (node->next) {
- node = node->next;
- if (!node->value.s || !node->value.len)
- return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
- if (node->next)
- return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
- value = &node->value;
- } else {
- value = NULL;
- }
- /* search for the profile */
- profile = search_dlg_profile( profile_name );
- if (profile==NULL)
- return init_mi_tree( 404, MI_SSTR("Profile not found"));
- rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
- if (rpl_tree==0)
- return 0;
- rpl = &rpl_tree->node;
- /* go through the hash and print the dialogs */
- if (profile->has_value==0 || value==NULL) {
- /* no value */
- lock_get( &profile->lock );
- for ( i=0 ; i< profile->size ; i++ ) {
- ph = profile->entries[i].first;
- if(ph) {
- do {
- /* print dialog */
- if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
- goto error;
- /* next */
- ph=ph->next;
- }while( ph!=profile->entries[i].first );
- }
- }
- lock_release( &profile->lock );
- } else {
- /* check for value also */
- lock_get( &profile->lock );
- for ( i=0 ; i< profile->size ; i++ ) {
- ph = profile->entries[i].first;
- if(ph) {
- do {
- if ( value->len==ph->value.len &&
- memcmp(value->s,ph->value.s,value->len)==0 ) {
- /* print dialog */
- if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
- goto error;
- }
- /* next */
- ph=ph->next;
- }while( ph!=profile->entries[i].first );
- }
- }
- lock_release( &profile->lock );
- }
- return rpl_tree;
- error:
- free_mi_tree(rpl_tree);
- return NULL;
- }
- /**
- * json serialization of dialog profiles
- */
- int dlg_profiles_to_json(dlg_cell_t *dlg, srjson_doc_t *jdoc)
- {
- dlg_profile_link_t *l;
- srjson_t *aj = NULL;
- srjson_t *pj = NULL;
- LM_DBG("serializing profiles for dlg[%u:%u]\n",
- dlg->h_entry, dlg->h_id);
- if(dlg==NULL || dlg->profile_links==NULL)
- return -1;
- LM_DBG("start of serializing profiles for dlg[%u:%u]\n",
- dlg->h_entry, dlg->h_id);
- for (l = dlg->profile_links ; l ; l=l->next) {
- if(aj==NULL)
- {
- aj = srjson_CreateArray(jdoc);
- if(aj==NULL)
- {
- LM_ERR("cannot create json profiles array object\n");
- goto error;
- }
- }
- pj = srjson_CreateObject(jdoc);
- if(pj==NULL)
- {
- LM_ERR("cannot create json dynamic profiles obj\n");
- goto error;
- }
- srjson_AddStrStrToObject(jdoc, pj,
- "name", 4,
- l->profile->name.s, l->profile->name.len);
- if(l->profile->has_value)
- {
- srjson_AddStrStrToObject(jdoc, pj,
- "value", 5,
- l->hash_linker.value.s, l->hash_linker.value.len);
- }
- if(l->hash_linker.puid[0]!='\0')
- srjson_AddStringToObject(jdoc, pj, "puid", l->hash_linker.puid);
- if(l->hash_linker.expires!=0)
- srjson_AddNumberToObject(jdoc, pj, "expires", l->hash_linker.expires);
- if(l->hash_linker.flags!=0)
- srjson_AddNumberToObject(jdoc, pj, "flags", l->hash_linker.flags);
- srjson_AddItemToArray(jdoc, aj, pj);
- }
- if(jdoc->root==NULL)
- {
- jdoc->root = srjson_CreateObject(jdoc);
- if(jdoc->root==NULL)
- {
- LM_ERR("cannot create json root\n");
- goto error;
- }
- }
- if(aj!=NULL)
- srjson_AddItemToObject(jdoc, jdoc->root, "profiles", aj);
- if(jdoc->buf.s != NULL)
- {
- jdoc->free_fn(jdoc->buf.s);
- jdoc->buf.s = NULL;
- jdoc->buf.len = 0;
- }
- jdoc->buf.s = srjson_PrintUnformatted(jdoc, jdoc->root);
- if(jdoc->buf.s!=NULL)
- {
- jdoc->buf.len = strlen(jdoc->buf.s);
- LM_DBG("serialized profiles for dlg[%u:%u] = [[%.*s]]\n",
- dlg->h_entry, dlg->h_id, jdoc->buf.len, jdoc->buf.s);
- return 0;
- }
- return -1;
- error:
- srjson_Delete(jdoc, aj);
- return -1;
- }
- /**
- * json de-serialization of dialog profiles
- */
- int dlg_json_to_profiles(dlg_cell_t *dlg, srjson_doc_t *jdoc)
- {
- srjson_t *aj = NULL;
- srjson_t *it = NULL;
- srjson_t *jt = NULL;
- dlg_profile_table_t *profile;
- str name;
- str val;
- str puid;
- time_t expires;
- int flags;
- if(dlg==NULL || jdoc==NULL || jdoc->buf.s==NULL)
- return -1;
- if(jdoc->root == NULL)
- {
- jdoc->root = srjson_Parse(jdoc, jdoc->buf.s);
- if(jdoc->root == NULL)
- {
- LM_ERR("invalid json doc [[%s]]\n", jdoc->buf.s);
- return -1;
- }
- }
- aj = srjson_GetObjectItem(jdoc, jdoc->root, "profiles");
- if(aj!=NULL)
- {
- for(it=aj->child; it; it = it->next)
- {
- name.s = val.s = puid.s = NULL;
- expires = 0; flags = 0;
- for(jt = it->child; jt; jt = jt->next) {
- if(strcmp(jt->string, "name")==0) {
- name.s = jt->valuestring;
- name.len = strlen(name.s);
- } else if(strcmp(jt->string, "value")==0) {
- val.s = jt->valuestring;
- val.len = strlen(val.s);
- } else if(strcmp(jt->string, "puid")==0) {
- puid.s = jt->valuestring;
- puid.len = strlen(puid.s);
- } else if(strcmp(jt->string, "expires")==0) {
- expires = (time_t)jt->valueint;
- } else if(strcmp(jt->string, "flags")==0) {
- flags = jt->valueint;
- }
- }
- if(name.s==NULL)
- continue;
- profile = search_dlg_profile(&name);
- if(profile==NULL)
- {
- LM_ERR("profile [%.*s] not found\n", name.len, name.s);
- continue;
- }
- if(val.s!=NULL) {
- if(profile->has_value)
- {
- if(dlg_add_profile(dlg, &val, profile, &puid, expires, flags) < 0)
- LM_ERR("dynamic profile cannot be added, ignore!\n");
- else
- LM_DBG("dynamic profile added [%s : %s]\n", name.s, val.s);
- }
- } else {
- if(!profile->has_value)
- {
- if(dlg_add_profile(dlg, NULL, profile, &puid, expires, flags) < 0)
- LM_ERR("static profile cannot be added, ignore!\n");
- else
- LM_DBG("static profile added [%s]\n", name.s);
- }
- }
- }
- }
- return 0;
- }
- /*!
- *
- */
- int dlg_cmd_remote_profile(str *cmd, str *pname, str *value, str *puid,
- time_t expires, int flags)
- {
- dlg_profile_table_t *dprofile;
- int ret;
- if(cmd==NULL || cmd->s==NULL || cmd->len<=0
- || pname==NULL || pname->s==NULL || pname->len<=0
- || puid==NULL || puid->s==NULL || puid->len<=0) {
- LM_ERR("invalid parameters\n");
- return -1;
- }
- dprofile = search_dlg_profile(pname);
- if(dprofile==NULL) {
- LM_ERR("profile [%.*s] not found\n", pname->len, pname->s);
- return -1;
- }
- if(dprofile->has_value) {
- if(value==NULL || value->s==NULL || value->len<=0) {
- LM_ERR("profile [%.*s] requires a value\n", pname->len, pname->s);
- return -1;
- }
- }
- if(cmd->len==3 && strncmp(cmd->s, "add", 3)==0) {
- if(value && value->s && value->len>0) {
- ret = dlg_add_profile(NULL, value, dprofile, puid, expires, flags);
- } else {
- ret = dlg_add_profile(NULL, NULL, dprofile, puid, expires, flags);
- }
- if(ret<0) {
- LM_ERR("failed to add to profile [%.*s]\n", pname->len, pname->s);
- return -1;
- }
- } else if(cmd->len==2 && strncmp(cmd->s, "rm", 2)==0) {
- ret = remove_profile(dprofile, value, puid);
- return ret;
- } else {
- LM_ERR("unknown command [%.*s]\n", cmd->len, cmd->s);
- return -1;
- }
- return 0;
- }
|