Module: sip-router Branch: master Commit: 8d2e86cabe73195463937f4945f600ceabe3585a URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=8d2e86ca...
Author: Daniel-Constantin Mierla miconda@gmail.com Committer: Daniel-Constantin Mierla miconda@gmail.com Date: Fri Aug 22 00:16:01 2014 +0200
dialog: internal refactoring to allow adding remote profile
- this is a profile item without a local dialog - allow opperations to add or remove such profiles
---
modules/dialog/dlg_profile.c | 193 +++++++++++++++++++++++++++++++++--------- modules/dialog/dlg_profile.h | 1 + 2 files changed, 153 insertions(+), 41 deletions(-)
diff --git a/modules/dialog/dlg_profile.c b/modules/dialog/dlg_profile.c index 0efa1cd..aba19c4 100644 --- a/modules/dialog/dlg_profile.c +++ b/modules/dialog/dlg_profile.c @@ -297,6 +297,73 @@ void destroy_linkers(struct dlg_profile_link *linker)
/*! + * \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 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; + struct dlg_profile_hash *kh; + + hash = calc_hash_profile(value, puid, profile); + lock_get(&profile->lock ); + p_entry = &profile->entries[hash]; + lh = p_entry->first; + while(lh) { + kh = lh->next; + 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 = kh; + } + lock_release(&profile->lock ); + return 0; +} + + +/*! * \brief Cleanup a profile * \param msg SIP message * \param flags unused @@ -328,30 +395,37 @@ int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param ) }
- /*! - * \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 + * \brief Link a dialog profile + * \param linker dialog linker + * \param vkey key for profile hash table */ -inline static unsigned int calc_hash_profile(str *value1, str *value2, - dlg_profile_table_t *profile) +static void link_profile(struct dlg_profile_link *linker, str *vkey) { - if (profile->has_value) { - /* do hash over the value1 */ - return core_hash( value1, NULL, profile->size); + unsigned int hash; + struct dlg_profile_entry *p_entry; + struct dlg_entry *d_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 { - /* do hash over the value2 */ - if(value2) - return core_hash( value2, NULL, profile->size); - return 0; + 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 @@ -379,24 +453,7 @@ static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *d linker->hash_linker.dlg = dlg; }
- /* calculate the hash position */ - hash = calc_hash_profile(&linker->hash_linker.value, &dlg->callid, 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 ); + link_profile(linker, &dlg->callid); }
@@ -461,8 +518,9 @@ int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *p } memset(linker, 0, sizeof(struct dlg_profile_link));
- /* set backpointer to profile */ + /* set backpointers to profile and linker (itself) */ linker->profile = profile; + linker->hash_linker.linker = linker;
/* set the value */ if (profile->has_value) { @@ -514,9 +572,7 @@ int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profi str *puid, time_t expires, int flags) { dlg_profile_link_t *linker; - - if (dlg==NULL) - return -1; + str vkey;
/* build new linker */ linker = (struct dlg_profile_link*)shm_malloc( @@ -527,8 +583,9 @@ int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profi } memset(linker, 0, sizeof(struct dlg_profile_link));
- /* set backpointer to profile */ + /* set backpointers to profile and linker (itself) */ linker->profile = profile; + linker->hash_linker.linker = linker;
/* set the value */ if (profile->has_value) { @@ -539,6 +596,7 @@ int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profi } 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); @@ -548,7 +606,13 @@ int dlg_add_profile(dlg_cell_t *dlg, str *value, struct dlg_profile_table *profi linker->hash_linker.flags = flags;
/* add linker directly to the dialog and profile */ - link_dlg_profile( linker, dlg); + if(dlg!=NULL) { + link_dlg_profile(linker, dlg); + } else { + vkey.s = linker->hash_linker.puid; + vkey.len = linker->hash_linker.puid_len; + link_profile(linker, &vkey); + } return 0; error: return -1; @@ -1187,3 +1251,50 @@ int dlg_json_to_profiles(dlg_cell_t *dlg, srjson_doc_t *jdoc) } 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; +} diff --git a/modules/dialog/dlg_profile.h b/modules/dialog/dlg_profile.h index 00ef276..0773fe1 100644 --- a/modules/dialog/dlg_profile.h +++ b/modules/dialog/dlg_profile.h @@ -55,6 +55,7 @@ typedef struct dlg_profile_hash { int puid_len; time_t expires; int flags; + struct dlg_profile_link *linker; struct dlg_profile_hash *next; struct dlg_profile_hash *prev; unsigned int hash; /*!< position in the hash table */