src/modules/ims_charging/ro_session_hash.c
acbbae2a
 /* 
  * File:   ro_session_hash.c
  * Author: Jason Penton
  *
  * Created on 08 April 2011, 1:10 PM
  */
 
 #include "ro_session_hash.h"
88a7b00c
 #include "ims_ro.h"
acbbae2a
 
84634ac0
 #define MAX_ROSESSION_LOCKS  2048
 #define MIN_ROSESSION_LOCKS  2
acbbae2a
 
 /*! global ro_session table */
 struct ro_session_table *ro_session_table = 0;
 
 /*!
  * \brief Link a ro_session structure
  * \param ro_session Ro Session
  * \param n extra increments for the reference counter
  */
 void link_ro_session(struct ro_session *ro_session, int n) {
     struct ro_session_entry *ro_session_entry;
88a7b00c
     
508786fc
     LM_DBG("Linking Ro session [%.*s] into entries hash index [%d]\n", ro_session->ro_session_id.len, ro_session->ro_session_id.s, ro_session->h_entry);
acbbae2a
 
     ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
 
     ro_session_lock(ro_session_table, ro_session_entry);
 
     ro_session->h_id = ro_session_entry->next_id++;
     if (ro_session_entry->first == 0) {
         ro_session_entry->first = ro_session_entry->last = ro_session;
     } else {
         ro_session_entry->last->next = ro_session;
         ro_session->prev = ro_session_entry->last;
         ro_session_entry->last = ro_session;
     }
 
     ro_session->ref += 1 + n;
     
     ro_session_unlock(ro_session_table, ro_session_entry);
 
     return;
 }
 
 /*!
  * \brief Refefence an ro_session with locking
  * \see ref_ro_session_unsafe
  * \param ro_session Ro Session
  * \param cnt increment for the reference counter
  */
44b80def
 void ref_ro_session_helper(struct ro_session *ro_session, unsigned int cnt, unsigned int mustlock, char *fname, int fline) {
acbbae2a
     struct ro_session_entry *ro_session_entry;
 
44b80def
 	LM_DBG("ref op on %p with %d from %s:%d\n", ro_session, cnt, fname, fline);
acbbae2a
     ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
 
44b80def
     if (mustlock)
 		ro_session_lock(ro_session_table, ro_session_entry);
     
 	ref_ro_session_unsafe(ro_session, cnt);
     
 	if (mustlock)
 		ro_session_unlock(ro_session_table, ro_session_entry);
acbbae2a
 }
 
 /*!
  * \brief Unreference an ro_session with locking
  * \see unref_ro_session_unsafe
  * \param ro_session Ro Session
  * \param cnt decrement for the reference counter
  */
44b80def
 void unref_ro_session_helper(struct ro_session *ro_session, unsigned int cnt, unsigned int mustlock, char *fname, int fline) {
acbbae2a
     struct ro_session_entry *ro_session_entry;
 
44b80def
 	LM_DBG("unref op on %p with %d from %s:%d\n", ro_session, cnt, fname, fline);
acbbae2a
 
44b80def
 	ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
 	if (mustlock)
 		ro_session_lock(ro_session_table, ro_session_entry);
acbbae2a
     unref_ro_session_unsafe(ro_session, cnt, ro_session_entry);
44b80def
 	if (mustlock)
 		ro_session_unlock(ro_session_table, ro_session_entry);
acbbae2a
 }
 
 /*!
  * \brief Initialize the global ro_session table
  * \param size size of the table
  * \return 0 on success, -1 on failure
  */
 int init_ro_session_table(unsigned int size) {
     unsigned int n;
     unsigned int i;
 
84634ac0
     ro_session_table = (struct ro_session_table*) shm_malloc(sizeof (struct ro_session_table) + size * sizeof (struct ro_session_entry));
acbbae2a
     if (ro_session_table == 0) {
         LM_ERR("no more shm mem (1)\n");
         goto error0;
     }
 
     memset(ro_session_table, 0, sizeof (struct ro_session_table));
     ro_session_table->size = size;
     ro_session_table->entries = (struct ro_session_entry*) (ro_session_table + 1);
 
84634ac0
     n = (size < MAX_ROSESSION_LOCKS) ? size : MAX_ROSESSION_LOCKS;
     for (; n >= MIN_ROSESSION_LOCKS; n--) {
acbbae2a
         ro_session_table->locks = lock_set_alloc(n);
         if (ro_session_table->locks == 0)
             continue;
         if (lock_set_init(ro_session_table->locks) == 0) {
             lock_set_dealloc(ro_session_table->locks);
             ro_session_table->locks = 0;
             continue;
         }
         ro_session_table->locks_no = n;
         break;
     }
 
     if (ro_session_table->locks == 0) {
84634ac0
         LM_ERR("unable to allocate at least %d locks for the hash table\n",
                 MIN_ROSESSION_LOCKS);
acbbae2a
         goto error1;
     }
 
     for (i = 0; i < size; i++) {
         memset(&(ro_session_table->entries[i]), 0, sizeof (struct ro_session_entry));
bcdbcfc5
         ro_session_table->entries[i].next_id = kam_rand() % (3*size);
acbbae2a
         ro_session_table->entries[i].lock_idx = i % ro_session_table->locks_no;
     }
 
     return 0;
 error1:
     shm_free(ro_session_table);
84634ac0
     ro_session_table = NULL;
acbbae2a
 error0:
     return -1;
 }
 
88a7b00c
 int put_ro_session_on_wait(struct ro_session* session) {
     LM_DBG("Putting Ro session [%p] - [%.*s] on wait queue for deletion\n", session, session->ro_session_id.len, session->ro_session_id.s);
     session->event_type = delayed_delete;
     session->last_event_timestamp = get_current_time_micro();
     insert_ro_timer(&session->ro_tl, 120);
     
     return 0;
 }
 
acbbae2a
 /*!
  * \brief Destroy an ro_session and free memory
  * \param ro_session destroyed Ro Session
  */
 inline void destroy_ro_session(struct ro_session *ro_session) {
 
     LM_DBG("destroying Ro Session %p\n", ro_session);
 
     remove_ro_timer(&ro_session->ro_tl);
     
     if (ro_session->ro_session_id.s && (ro_session->ro_session_id.len > 0)) {
         shm_free(ro_session->ro_session_id.s);
     }
639ce584
 
acbbae2a
     shm_free(ro_session);
 }
 
 /*!
  * \brief Destroy the global Ro session table
  */
 void destroy_dlg_table(void) {
     struct ro_session *ro_session, *l_ro_session;
     unsigned int i;
 
     if (ro_session_table == 0)
         return;
 
     if (ro_session_table->locks) {
         lock_set_destroy(ro_session_table->locks);
         lock_set_dealloc(ro_session_table->locks);
     }
 
     for (i = 0; i < ro_session_table->size; i++) {
         ro_session = ro_session_table->entries[i].first;
         while (ro_session) {
             l_ro_session = ro_session;
             ro_session = ro_session->next;
             destroy_ro_session(l_ro_session);
         }
 
     }
 
     shm_free(ro_session_table);
     ro_session_table = 0;
 
     return;
 }
 
efcd3421
 struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_session_type, str *session_id, str *callid, str *asserted_identity, 
 	str* called_asserted_identity, str* mac, unsigned int dlg_h_entry, unsigned int dlg_h_id, unsigned int requested_secs, unsigned int validity_timeout,
2acd4448
 	int active_rating_group, int active_service_identifier, str *incoming_trunk_id, str *outgoing_trunk_id, str *pani, str *app_provided_party){
508786fc
     LM_DBG("Building Ro Session **********\n");
acbbae2a
     char *p;
88a7b00c
     unsigned int len = /*session_id->len + */callid->len + asserted_identity->len + called_asserted_identity->len + mac->len + 
2acd4448
         incoming_trunk_id->len + outgoing_trunk_id->len + pani->len + app_provided_party->len + sizeof (struct ro_session);
acbbae2a
     struct ro_session *new_ro_session = (struct ro_session*) shm_malloc(len);
 
     if (!new_ro_session) {
         LM_ERR("no more shm mem.\n");
         shm_free(new_ro_session);
         return 0;
     }
     
     LM_DBG("New Ro Session given memory at address [%p]\n", new_ro_session);
 
     memset(new_ro_session, 0, len);
5fd0a098
     
c7a148c5
 //    if (pani->len < MAX_PANI_LEN) {
 //		p = new_ro_session->pani;
 //		memcpy(p, pani->s, pani->len);
 //    }
acbbae2a
 
     new_ro_session->direction = direction;
     new_ro_session->auth_appid = auth_appid;
     new_ro_session->auth_session_type = auth_session_type;
 
88a7b00c
     new_ro_session->ro_tl.next = new_ro_session->ro_tl.prev;// = 0;
acbbae2a
     new_ro_session->ro_tl.timeout = 0; //requested_secs;
 
     new_ro_session->reserved_secs = requested_secs;
     new_ro_session->valid_for = validity_timeout;
 
a52ee4f0
     new_ro_session->hop_by_hop = 0;
acbbae2a
     new_ro_session->next = 0;
     new_ro_session->dlg_h_entry = dlg_h_entry;
     new_ro_session->dlg_h_id = dlg_h_id;
 
     new_ro_session->h_entry = dlg_h_entry; /* we will use the same entry ID as the dlg - saves us using our own hash function */
     new_ro_session->h_id = 0;
e0107368
     new_ro_session->ref = 1;
efcd3421
     
     new_ro_session->rating_group = active_rating_group;
     new_ro_session->service_identifier = active_service_identifier;
acbbae2a
 
     p = (char*) (new_ro_session + 1);
     new_ro_session->callid.s = p;
     new_ro_session->callid.len = callid->len;
     memcpy(p, callid->s, callid->len);
     p += callid->len;
 
574765a2
     new_ro_session->asserted_identity.s = p;
     new_ro_session->asserted_identity.len = asserted_identity->len;
     memcpy(p, asserted_identity->s, asserted_identity->len);
     p += asserted_identity->len;
acbbae2a
 
574765a2
     new_ro_session->called_asserted_identity.s = p;
     new_ro_session->called_asserted_identity.len = called_asserted_identity->len;
     memcpy(p, called_asserted_identity->s, called_asserted_identity->len);
     p += called_asserted_identity->len;
909a898a
     
63abc6f8
     new_ro_session->incoming_trunk_id.s = p;
     new_ro_session->incoming_trunk_id.len = incoming_trunk_id->len;
     memcpy(p, incoming_trunk_id->s, incoming_trunk_id->len);
     p += incoming_trunk_id->len;
     
     new_ro_session->outgoing_trunk_id.s = p;
     new_ro_session->outgoing_trunk_id.len = outgoing_trunk_id->len;
     memcpy(p, outgoing_trunk_id->s, outgoing_trunk_id->len);
     p += outgoing_trunk_id->len;
efcd3421
     
88a7b00c
     new_ro_session->mac.s = p;
     new_ro_session->mac.len = mac->len;
639ce584
     memcpy(p, mac->s, mac->len);
     p += mac->len;
c7a148c5
     
     new_ro_session->pani.s = p;
     memcpy(p, pani->s, pani->len);
     new_ro_session->pani.len = pani->len;
     p += pani->len;
acbbae2a
 
2acd4448
     new_ro_session->app_provided_party.s = p;
     memcpy(p, app_provided_party->s, app_provided_party->len);
     new_ro_session->app_provided_party.len = app_provided_party->len;
     p += app_provided_party->len;
 
acbbae2a
     if (p != (((char*) new_ro_session) + len)) {
         LM_ERR("buffer overflow\n");
         shm_free(new_ro_session);
         return 0;
     }
 
     return new_ro_session;
 
 }
 
 /*!
  * \brief Lookup an Ro session in the global list
  * \param h_entry number of the hash table entry
  * \param h_id id of the hash table entry
  * \return ro_session on success, NULL on failure
  */
 struct ro_session* lookup_ro_session(unsigned int h_entry, str* callid, int direction, unsigned int *del) {
     struct ro_session *ro_session;
     struct ro_session_entry *ro_session_entry;
 
     if (del != NULL)
         *del = 0;
 
     if (h_entry >= ro_session_table->size)
         goto not_found;
     ro_session_entry = &(ro_session_table->entries[h_entry]);
 
     ro_session_lock(ro_session_table, ro_session_entry);
 
     for (ro_session = ro_session_entry->first; ro_session; ro_session = ro_session->next) {
         if ((direction==0 || direction==ro_session->direction) && (strncmp(ro_session->callid.s, callid->s, callid->len)==0)) {
44b80def
 		ref_ro_session(ro_session, 1, 0);
acbbae2a
             LM_DBG("ref ro_session %p with 1 -> %d\n", ro_session, ro_session->ref);
             ro_session_unlock(ro_session_table, ro_session_entry);
             LM_DBG("ro_session id=%u found on entry %u\n", ro_session->h_id, h_entry);
             return ro_session;
         }
     }
 
     ro_session_unlock(ro_session_table, ro_session_entry);
 not_found:
     LM_DBG("no ro_session for callid=%.*s found on entry %u\n", callid->len, callid->s, h_entry);
     return 0;
 }
 
909a898a
 /*
  * \brief free impu_data parcel
  */
 void free_impu_data(struct impu_data *impu_data) {
     if(impu_data){
 	shm_free(impu_data);
 	impu_data=0;
     }
 }