浏览代码

modules/ims: dialog, usrloc, qos and charging modules for IMS
- dialog_ng - some fixes related to ref counting and state machine
- usrlocs - fixes/improvements to internal storage for both P-CSCF and S-CSCF usrloc storage
- registrars - fixes/improvements to the registrars for S-CSCF, P-CSCF
- ims_charging - align to updated api for dialog_ng
- ims_qos - align to updated api for dialog_ng

jaybeepee 10 年之前
父节点
当前提交
88a7b00cf9
共有 70 个文件被更改,包括 4290 次插入3361 次删除
  1. 1 0
      modules/dialog_ng/Makefile
  2. 1 3
      modules/dialog_ng/dialog.c
  3. 1 0
      modules/dialog_ng/dlg_cb.c
  4. 0 2
      modules/dialog_ng/dlg_cb.h
  5. 12 5
      modules/dialog_ng/dlg_db_handler.c
  6. 1201 780
      modules/dialog_ng/dlg_handlers.c
  7. 20 0
      modules/dialog_ng/dlg_handlers.h
  8. 175 98
      modules/dialog_ng/dlg_hash.c
  9. 66 18
      modules/dialog_ng/dlg_hash.h
  10. 103 95
      modules/dialog_ng/dlg_profile.c
  11. 11 11
      modules/dialog_ng/dlg_profile.h
  12. 2 4
      modules/dialog_ng/dlg_req_within.c
  13. 74 35
      modules/dialog_ng/dlg_var.c
  14. 27 21
      modules/dialog_ng/dlg_var.h
  15. 1 0
      modules/ims_charging/Makefile
  16. 1 1
      modules/ims_charging/Ro_data.c
  17. 100 88
      modules/ims_charging/dialog.c
  18. 2 1
      modules/ims_charging/dialog.h
  19. 286 286
      modules/ims_charging/ims_ro.c
  20. 2 0
      modules/ims_charging/ims_ro.h
  21. 11 30
      modules/ims_charging/mod.c
  22. 4 4
      modules/ims_charging/ro_db_handler.c
  23. 16 10
      modules/ims_charging/ro_session_hash.c
  24. 11 10
      modules/ims_charging/ro_session_hash.h
  25. 203 208
      modules/ims_charging/ro_timer.c
  26. 15 3
      modules/ims_qos/cdpeventprocessor.c
  27. 64 25
      modules/ims_qos/mod.c
  28. 26 36
      modules/ims_qos/rx_aar.c
  29. 7 1
      modules/ims_qos/rx_aar.h
  30. 15 6
      modules/ims_qos/rx_authdata.c
  31. 6 2
      modules/ims_qos/rx_authdata.h
  32. 0 107
      modules/ims_registrar_pcscf/lookup.c
  33. 0 59
      modules/ims_registrar_pcscf/lookup.h
  34. 401 323
      modules/ims_registrar_pcscf/notify.c
  35. 0 112
      modules/ims_registrar_pcscf/reg_mod.c
  36. 32 16
      modules/ims_registrar_pcscf/save.c
  37. 1 1
      modules/ims_registrar_pcscf/save.h
  38. 143 144
      modules/ims_registrar_pcscf/service_routes.c
  39. 0 5
      modules/ims_registrar_pcscf/service_routes.h
  40. 1 1
      modules/ims_registrar_scscf/cxdx_avp.c
  41. 19 4
      modules/ims_registrar_scscf/cxdx_callbacks.c
  42. 1 0
      modules/ims_registrar_scscf/cxdx_sar.c
  43. 1 1
      modules/ims_registrar_scscf/lookup.c
  44. 7 0
      modules/ims_registrar_scscf/reg_mod.c
  45. 223 168
      modules/ims_registrar_scscf/registrar_notify.c
  46. 4 2
      modules/ims_registrar_scscf/registrar_notify.h
  47. 11 2
      modules/ims_registrar_scscf/reply.c
  48. 125 85
      modules/ims_registrar_scscf/save.c
  49. 2 16
      modules/ims_registrar_scscf/usrloc_cb.c
  50. 76 51
      modules/ims_usrloc_pcscf/pcontact.c
  51. 2 2
      modules/ims_usrloc_pcscf/pcontact.h
  52. 241 206
      modules/ims_usrloc_pcscf/udomain.c
  53. 4 4
      modules/ims_usrloc_pcscf/udomain.h
  54. 4 0
      modules/ims_usrloc_pcscf/ul_mod.c
  55. 8 46
      modules/ims_usrloc_pcscf/usrloc.c
  56. 144 128
      modules/ims_usrloc_pcscf/usrloc.h
  57. 25 14
      modules/ims_usrloc_pcscf/usrloc_db.c
  58. 12 4
      modules/ims_usrloc_pcscf/usrloc_db.h
  59. 184 0
      modules/ims_usrloc_scscf/contact_dlg_handlers.c
  60. 1 1
      modules/ims_usrloc_scscf/dlist.c
  61. 1 1
      modules/ims_usrloc_scscf/dlist.h
  62. 63 43
      modules/ims_usrloc_scscf/impurecord.c
  63. 4 4
      modules/ims_usrloc_scscf/impurecord.h
  64. 9 8
      modules/ims_usrloc_scscf/ucontact.c
  65. 3 3
      modules/ims_usrloc_scscf/ucontact.h
  66. 43 3
      modules/ims_usrloc_scscf/udomain.c
  67. 15 1
      modules/ims_usrloc_scscf/ul_mod.c
  68. 7 7
      modules/ims_usrloc_scscf/usrloc.c
  69. 4 3
      modules/ims_usrloc_scscf/usrloc.h
  70. 5 3
      modules/ims_usrloc_scscf/usrloc_db.c

+ 1 - 0
modules/dialog_ng/Makefile

@@ -12,4 +12,5 @@ SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules

+ 1 - 3
modules/dialog_ng/dialog.c

@@ -55,8 +55,6 @@ static char* profiles_wv_s = NULL;
 static char* profiles_nv_s = NULL;
 int detect_spirals = 1;
 str dlg_extra_hdrs = {NULL, 0};
-int initial_cbs_inscript = 1;
-
 str dlg_bridge_controller = str_init("sip:[email protected]");
 
 str ruri_pvar_param = str_init("$ru");
@@ -792,7 +790,7 @@ static int w_dlg_terminate(struct sip_msg *msg, char *side, char *r) {
         }
     }
 
-    dlg = get_current_dialog(msg);
+    dlg = dlg_get_msg_dialog(msg);
     //dlg_get_ctx_dialog();
     if (!dlg) {
         LM_DBG("Unable to find dialog for terminate\n");

+ 1 - 0
modules/dialog_ng/dlg_cb.c

@@ -234,6 +234,7 @@ void run_load_callbacks( void )
 void run_create_callbacks(struct dlg_cell *dlg, struct sip_msg *msg)
 {
 	struct dlg_callback *cb;
+        LM_DBG("Running DLG_CREATED callbacks\n");
 
 	if (create_cbs==NULL || create_cbs==POINTER_CLOSED_MARKER || create_cbs->first==NULL)
 		return;

+ 0 - 2
modules/dialog_ng/dlg_cb.h

@@ -70,8 +70,6 @@ typedef int (*set_dlg_variable_f)( str* callid, str* ftag, str* ttag,
 typedef str* (*get_dlg_variable_f)( str *callid, str *ftag, str *ttag,
                                     str* key);
 
-typedef struct dlg_cell* (*get_current_dlg_f)( struct sip_msg* msg);
-
 #define DLGCB_LOADED          (1<<0)
 #define DLGCB_CREATED         (1<<1)
 #define DLGCB_FAILED          (1<<2)

+ 12 - 5
modules/dialog_ng/dlg_db_handler.c

@@ -426,7 +426,7 @@ static int load_dialog_out_from_db(struct dlg_cell *dlg, str *did, int fetch_num
 			GET_STR_VALUE(to_uri,	values, DLGO_TO_URI_IDX, 	1, 0);
 			GET_STR_VALUE(to_tag,	values, DLGO_TO_TAG_IDX, 	1, 0);
 
-			dlg_out	= build_new_dlg_out(dlg, &to_uri, &to_tag);
+			dlg_out	= build_new_dlg_out(dlg, &to_uri, &to_tag, 0);
 
 			if (!dlg_out) {
 				LM_ERR("Error creating dlg_out cell\n");
@@ -534,7 +534,7 @@ static int load_dialog_info_from_db(int dlg_hash_size, int fetch_num_rows)
 			}
 
 			/*link the dialog*/
-			link_dlg(dlg, 0);
+			link_dlg(dlg, 0, 0);
 
 			GET_STR_VALUE(did, 		values, DLGI_DID_COL_IDX,		1, 0);
 			update_dlg_did(dlg, &did);
@@ -721,7 +721,7 @@ static int load_dialog_vars_from_db(int fetch_num_rows)
 					if (dlg->h_id == VAL_INT(values+1)) {
 						str key = { VAL_STR(values+2).s, strlen(VAL_STRING(values+2)) };
 						str value = { VAL_STR(values+3).s, strlen(VAL_STRING(values+3)) };
-						set_dlg_variable_unsafe(dlg, &key, &value, 1);
+						set_dlg_variable_unsafe(dlg, &key, &value);
 						break;
 					}
 					dlg = dlg->next;
@@ -886,8 +886,14 @@ error:
 
 int update_dialog_out_dbinfo_unsafe(struct dlg_cell * cell)
 {
+    	str x = {0,0};
+
 	struct dlg_cell_out *dlg_out	= cell->dlg_entry_out.first;
-	str x = {0,0};
+        if (!dlg_out) {
+            LM_DBG("no out dialogs to update\n");
+            return 0;
+        }
+            
 	if(use_dialog_out_table()!=0)
 		return -1;
 
@@ -1044,8 +1050,9 @@ int update_dialog_dbinfo_unsafe(struct dlg_cell * cell)
 		VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ENTRY_COL_IDX))	= cell->h_entry;
 		VAL_INT(GET_FIELD_IDX(values, DLGI_HASH_ID_COL_IDX))	= cell->h_id;
 		VAL_INT(GET_FIELD_IDX(values, DLGI_START_TIME_COL_IDX))	= cell->start_ts;
-		VAL_INT(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX))		= cell->state;
+		VAL_INT(GET_FIELD_IDX(values, DLGI_STATE_COL_IDX))	= cell->state;
 		VAL_INT(GET_FIELD_IDX(values, DLGI_TIMEOUT_COL_IDX))	= (unsigned int)( (unsigned int)time(0) + cell->tl.timeout - get_ticks() );
+                VAL_INT(GET_FIELD_IDX(values, DLGI_TOROUTE_INDEX_COL_IDX)) = cell->toroute;
 
 		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_CALLID_COL_IDX), cell->callid);
 		SET_STR_VALUE(GET_FIELD_IDX(values, DLGI_DID_COL_IDX), cell->did);

文件差异内容过多而无法显示
+ 1201 - 780
modules/dialog_ng/dlg_handlers.c


+ 20 - 0
modules/dialog_ng/dlg_handlers.h

@@ -90,6 +90,15 @@ void destroy_dlg_handlers(void);
 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
 	struct cell* t, unsigned int leg, str *tag);
 
+/*!
+ * \brief Clone dialog internal unique id to shared memory
+ */
+dlg_iuid_t *dlg_get_iuid_shm_clone(dlg_cell_t *dlg);
+
+/*!
+ * \brief Free dialog internal unique id stored in shared memory
+ */
+void dlg_iuid_sfree(void *iuid);
 
 /*!
  * \brief Function that is registered as TM callback and called on requests
@@ -99,6 +108,7 @@ int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
  */
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param);
 
+void dlg_onreply(struct cell* t, int type, struct tmcb_params *param);
 
 /*!
  * \brief Function that is registered as RR callback for dialog tracking
@@ -136,6 +146,16 @@ void dlg_ontimeout( struct dlg_tl *tl);
  */ 
 int dlg_new_dialog(struct sip_msg *msg, struct cell *t, const int run_initial_cbs);
 
+/*!
+ * \brief add dlg structure to tm callbacks
+ * \param t current transaction
+ * \param req current sip request
+ * \param dlg current dialog
+ * \param smode if the sip request was spiraled
+ * \return 0 on success, -1 on failure
+ */
+int dlg_set_tm_callbacks(tm_cell_t *t, sip_msg_t *req, dlg_cell_t *dlg,
+		int smode);
 
 /*!
  * \brief Function that returns the dialog lifetime as pseudo-variable

+ 175 - 98
modules/dialog_ng/dlg_hash.c

@@ -17,6 +17,7 @@
 #include "dlg_profile.h"
 #include "dlg_handlers.h"
 #include "dlg_db_handler.h"
+#include <execinfo.h>
 
 #define MAX_LDG_LOCKS  2048
 #define MIN_LDG_LOCKS  2
@@ -69,6 +70,24 @@ static int dlg_hash_size_out = 4096;
 		}\
 	}while(0)
 
+inline static int backtrace2str(char* buf, int size)
+{
+        void* bt[32];
+        int bt_size, i;
+        char** bt_strs;
+
+        bt_size=backtrace(bt, sizeof(bt)/sizeof(bt[0]));
+        bt_strs=backtrace_symbols(bt, bt_size);
+        if (bt_strs){
+                /*if (bt_size>16) bt_size=16;*/ /* go up only 12 entries */
+                for (i=0; i< bt_size; i++){
+                        /* try to isolate only the function name*/
+                        LM_DBG("BACKTRACE: %s\n", bt_strs[i]);
+                }
+        }
+        return 0;
+}
+
 /*!
  * \brief Initialize the global dialog table
  * \param size size of the table
@@ -197,9 +216,7 @@ inline void destroy_dlg(struct dlg_cell *dlg) {
     LM_DBG("About to run dlg callback for destroy\n");
     run_dlg_callbacks(DLGCB_DESTROY, dlg, NULL, NULL, DLG_DIR_NONE, 0);
     LM_DBG("DONE: About to run dlg callback for destroy\n");
-    if (dlg == get_current_dlg_pointer())
-        reset_current_dlg_pointer();
-
+    
     if (dlg->cbs.first)
         destroy_dlg_callbacks_list(dlg->cbs.first);
 
@@ -468,14 +485,14 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
  * \param to_tag - dialog to_tag
  * \return created dlg_out structure on success, NULL otherwise
  */
-struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str* to_uri, str* to_tag) {
+struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str* to_uri, str* to_tag, str* branch) {
 
     struct dlg_cell_out *dlg_out;
     int len;
     char *p;
 
     //len = sizeof (struct dlg_cell_out) +dlg->did.len + to_tag->len + to_uri->len;
-    len = sizeof (struct dlg_cell_out) +to_tag->len + to_uri->len;
+    len = sizeof (struct dlg_cell_out) +to_tag->len + to_uri->len + branch->len;
 
     dlg_out = (struct dlg_cell_out*) shm_malloc(len);
     if (dlg_out == 0) {
@@ -489,10 +506,12 @@ struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str* to_uri, str* t
 
     p = (char*) (dlg_out + 1);
 
-    //dlg_out->did.s = p;
-    //dlg_out->did.len = dlg->did.len;
-    //memcpy(p, dlg->did.s, dlg->did.len);
-    //p += dlg->did.len;
+    if (branch->len > 0) {
+        dlg_out->branch.s = p;
+        dlg_out->branch.len = branch->len;
+        memcpy(p, branch->s, branch->len);
+        p += branch->len;
+    }
 
     dlg_out->to_uri.s = p;
     dlg_out->to_uri.len = to_uri->len;
@@ -697,61 +716,51 @@ int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq, str *to_
 
         //compare the to_tag passed parameter to all the dlg_out to_tag entry of the dlg parameter  (There could be multiple)
         while (dlg_out) {
-            LM_DBG("Searching out dialog with to_tag '%.*s' (looking for '%.*s')\n", dlg_out->to_tag.len, dlg_out->to_tag.s, to_tag->len, to_tag->s);
 
             if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
                 //this parameter matches we have found the dlg_out to update the cseq
 
                 if (leg == DLG_CALLER_LEG) {
-                    LM_DBG("Update Caller\n");
                     //update caller cseq
                     if (dlg_out->caller_cseq.s) {
-                        if (dlg_out->caller_cseq.len != cseq->len) {
+                        if (dlg_out->caller_cseq.len < cseq->len) {
                             shm_free(dlg_out->caller_cseq.s);
                             dlg_out->caller_cseq.s = (char*) shm_malloc(cseq->len);
                             if (dlg_out->caller_cseq.s == NULL)
                                 goto error;
                             dlg_out->caller_cseq.len = cseq->len;
+                            memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
                         }
-                        LM_DBG("Updating CSeq...\n");
-                        memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
-                        LM_DBG("CSeq is now '%.*s' (%p)\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s, dlg_out->caller_cseq.s);
                     } else {
                         dlg_out->caller_cseq.s = (char*) shm_malloc(cseq->len);
                         if (dlg_out->caller_cseq.s == NULL)
                             goto error;
 
                         dlg_out->caller_cseq.len = cseq->len;
-                        LM_DBG("Updating CSeq...\n");
                         memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
-                        LM_DBG("CSeq is now '%.*s' (%p)\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s, dlg_out->caller_cseq.s);
                     }
+
                 } else if (leg == DLG_CALLEE_LEG) {
-                    LM_DBG("Update Callee\n");
                     //update callee cseq
                     if (dlg_out->callee_cseq.s) {
-                        if (dlg_out->callee_cseq.len != cseq->len) {
+                        if (dlg_out->callee_cseq.len < cseq->len) {
                             shm_free(dlg_out->callee_cseq.s);
                             dlg_out->callee_cseq.s = (char*) shm_malloc(cseq->len);
                             if (dlg_out->callee_cseq.s == NULL)
                                 goto error;
 
                             dlg_out->callee_cseq.len = cseq->len;
+                            memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
                         }
-                        LM_DBG("Updating CSeq...\n");
-			memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
-                        LM_DBG("CSeq is now '%.*s' (%p)\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s, dlg_out->caller_cseq.s);
                     } else {
                         dlg_out->callee_cseq.s = (char*) shm_malloc(cseq->len);
                         if (dlg_out->callee_cseq.s == NULL)
                             goto error;
 
                         dlg_out->callee_cseq.len = cseq->len;
-
-                        LM_DBG("Updating CSeq...\n");
                         memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
-                        LM_DBG("CSeq is now '%.*s' (%p)\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s, dlg_out->caller_cseq.s);
                     }
+
                 }
             }
             dlg_out = dlg_out->next;
@@ -862,6 +871,7 @@ struct dlg_cell * lookup_dlg(unsigned int h_entry, unsigned int h_id) {
 
     for (dlg = d_entry->first; dlg; dlg = dlg->next) {
         if (dlg->h_id == h_id) {
+//            backtrace2str(0,0);
             ref_dlg_unsafe(dlg, 1);
             dlg_unlock(d_table, d_entry);
             LM_DBG("dialog id=%u found on entry %u\n", h_id, h_entry);
@@ -883,27 +893,32 @@ not_found:
  * \param ftag from tag
  * \param ttag to tag
  * \param dir direction
+ * \param mode let hash table slot locked if dialog is not found
  * \return dialog structure on success, NULL on failure
  */
 static inline struct dlg_cell * internal_get_dlg(unsigned int h_entry,
-        str *callid, str *ftag, str *ttag, unsigned int *dir) {
+        str *callid, str *ftag, str *ttag, unsigned int *dir, unsigned int mode) {
     struct dlg_cell *dlg;
-    struct dlg_entry *d_entry;
-
-    d_entry = &(d_table->entries[h_entry]);
-
-    dlg_lock(d_table, d_entry);
-
-    for (dlg = d_entry->first; dlg; dlg = dlg->next) {
-        /* Check callid / fromtag / totag */
-        if (match_dialog(dlg, callid, ftag, ttag, dir) == 1) {
-            ref_dlg_unsafe(dlg, 1);
-            dlg_unlock(d_table, d_entry);
-            return dlg;
-        }
-    }
+	struct dlg_entry *d_entry;
+
+	d_entry = &(d_table->entries[h_entry]);
+
+	dlg_lock( d_table, d_entry);
+      
+	for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
+		/* Check callid / fromtag / totag */
+		if (match_dialog( dlg, callid, ftag, ttag, dir)==1) {
+			ref_dlg_unsafe(dlg, 1);
+			dlg_unlock( d_table, d_entry);
+			LM_DBG("dialog callid='%.*s' found on entry %u, dir=%d\n",
+				callid->len, callid->s,h_entry,*dir);
+			return dlg;
+		}
+	}
 
-    dlg_unlock(d_table, d_entry);
+	if(likely(mode==0)) dlg_unlock( d_table, d_entry);
+	LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
+	return 0;
 
     return 0;
 }
@@ -926,13 +941,13 @@ static inline struct dlg_cell * internal_get_dlg(unsigned int h_entry,
  */
 struct dlg_cell * get_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir) {
     struct dlg_cell *dlg;
+    unsigned int he;
 
-    if ((dlg = internal_get_dlg(core_hash(callid, 0,
-            d_table->size), callid, ftag, ttag, dir)) == 0 &&
-            (dlg = internal_get_dlg(core_hash(callid, ttag->len
-            ? ttag : 0, d_table->size), callid, ftag, ttag, dir)) == 0) {
-        LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
+    he = core_hash(callid, 0, d_table->size);
+    dlg = internal_get_dlg(he, callid, ftag, ttag, dir, 0);
 
+    if (dlg == 0) {
+        LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
         return 0;
     }
     return dlg;
@@ -968,21 +983,23 @@ void link_dlg_out(struct dlg_cell *dlg, struct dlg_cell_out *dlg_out, int n) {
     LM_DBG("Done: link_dlg_out\n");
     return;
 }
-
 /*!
  * \brief Link a dialog structure
  * \param dlg dialog
  * \param n extra increments for the reference counter
+ * \param mode link in safe mode (0 - lock slot; 1 - don't)
  */
-void link_dlg(struct dlg_cell *dlg, int n) {
+void link_dlg(struct dlg_cell *dlg, int n, int mode) {
     struct dlg_entry *d_entry;
 
-    LM_DBG("Linking new dialog with h_entry: %u", dlg->h_entry);
     d_entry = &(d_table->entries[dlg->h_entry]);
 
-    dlg_lock(d_table, d_entry);
+    if (unlikely(mode == 0)) dlg_lock(d_table, d_entry);
 
-    dlg->h_id = d_entry->next_id++;
+    /* keep id 0 for special cases */
+    dlg->h_id = 1 + d_entry->next_id++;
+    if (dlg->h_id == 0) dlg->h_id = 1;
+    LM_DBG("linking dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
     if (d_entry->first == 0) {
         d_entry->first = d_entry->last = dlg;
     } else {
@@ -993,11 +1010,12 @@ void link_dlg(struct dlg_cell *dlg, int n) {
 
     ref_dlg_unsafe(dlg, 1 + n);
 
-    dlg_unlock(d_table, d_entry);
-
+    if (unlikely(mode == 0)) dlg_unlock(d_table, d_entry);
     return;
 }
 
+
+
 /*!
  * \brief Refefence a dialog with locking
  * \see ref_dlg_unsafe
@@ -1011,10 +1029,12 @@ void ref_dlg(struct dlg_cell *dlg, unsigned int cnt) {
     d_entry = &(d_table->entries[dlg->h_entry]);
 
     dlg_lock(d_table, d_entry);
+//    backtrace2str(0, 0);
     ref_dlg_unsafe(dlg, cnt);
     dlg_unlock(d_table, d_entry);
 }
 
+
 /*!
  * \brief Unreference a dialog with locking
  * \see unref_dlg_unsafe
@@ -1028,6 +1048,7 @@ void unref_dlg(struct dlg_cell *dlg, unsigned int cnt) {
     d_entry = &(d_table->entries[dlg->h_entry]);
 
     dlg_lock(d_table, d_entry);
+//    backtrace2str(0, 0);
     unref_dlg_unsafe(dlg, cnt, d_entry);
     dlg_unlock(d_table, d_entry);
 }
@@ -1062,8 +1083,6 @@ static inline void log_next_state_dlg(const int event, const struct dlg_cell * d
 void next_state_dlg(struct dlg_cell *dlg, int event,
         int *old_state, int *new_state, int *unref, str * to_tag) {
     struct dlg_entry *d_entry;
-    
-
 
     d_entry = &(d_table->entries[dlg->h_entry]);
 
@@ -1084,27 +1103,28 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
             switch (dlg->state) {
                 case DLG_STATE_UNCONFIRMED:
                 case DLG_STATE_EARLY:
-		    if (to_tag) {
-                        LM_DBG("Going to check if there is another active branch - we only change state to DELETED if there are no other active branches\n");
-                        while (dlg_out) {
-                            if (dlg_out->to_tag.len != to_tag->len || memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) != 0) {
-				if(dlg_out->deleted != 1) {
-				    LM_DBG("Found a dlg_out that is not for this event and is not in state deleted, therefore there is another active branch\n");
-				    delete = 0;
-                                    //we should delete this dlg_out tho...
-                                    dlg_out->deleted=1;
-				}
-                            }
-                            dlg_out = dlg_out->next;
-                        }
-                    } 
-		    if(delete) {
-			dlg->state = DLG_STATE_DELETED;
-			unref_dlg_unsafe(dlg, 1, d_entry);
-			*unref = 1;
-		    }
+//		    if (to_tag) {
+//                        LM_DBG("Going to check if there is another active branch - we only change state to DELETED if there are no other active branches\n");
+//                        while (dlg_out) {
+//                            if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
+//                                dlg_out->deleted=1;
+//                            } else {
+//                                if (dlg_out->deleted != 1) {
+//                                    LM_DBG("Found a dlg_out (to-tag: [%.*s]) that is not for this event and is not in state deleted, therefore there is another active branch\n", to_tag->len, to_tag->s);
+//                                    delete = 0;
+//                                }
+//                            }
+//                            dlg_out = dlg_out->next;
+//                        }
+//                    }
+                    if (delete) {
+                        dlg->state = DLG_STATE_DELETED;
+                        unref_dlg_unsafe(dlg, 1, d_entry);
+                        *unref = 1;
+                    }
                     break;
                 case DLG_STATE_CONFIRMED:
+                case DLG_STATE_CONFIRMED_NA:
                     unref_dlg_unsafe(dlg, 1, d_entry);
                     break;
                 case DLG_STATE_DELETED:
@@ -1128,18 +1148,6 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
             switch (dlg->state) {
                 case DLG_STATE_UNCONFIRMED:
                 case DLG_STATE_EARLY:
-		    if (to_tag) {
-                        LM_DBG("Going to check if there is another active branch - we only change state to DELETED if there are no other active branches\n");
-                        while (dlg_out) {
-                            if (dlg_out->to_tag.len != to_tag->len || memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) != 0) {
-				if(dlg_out->deleted != 1) {
-				    LM_DBG("Found a dlg_out that is not for this event and is not in state deleted, therefore there is another active branch\n");
-				    delete = 0;
-				}
-                            }
-                            dlg_out = dlg_out->next;
-                        }
-                    } 
 		    if(delete) {
 			dlg->state = DLG_STATE_DELETED;
 			*unref = 1;
@@ -1163,11 +1171,10 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
                     ref_dlg_unsafe(dlg, 1);
                 case DLG_STATE_UNCONFIRMED:
                 case DLG_STATE_EARLY:
-                    dlg->state = DLG_STATE_CONFIRMED;
-                    //TODO: check that the callbacks for confirmed are run
+                    dlg->state = DLG_STATE_CONFIRMED_NA;
                     break;
+                case DLG_STATE_CONFIRMED_NA:
                 case DLG_STATE_CONFIRMED:
-                    //check the to_tag passed parameter exists
                     if (to_tag) {
                         //compare the to_tag passed parameter to the dlg_out to_tag entry of the dlg parameter  (There should be only 1 dlg_out entry)
 
@@ -1191,19 +1198,13 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
                             //The parameter does not match so this is a concurrently confirmed call
                             //dlg->state = DLG_STATE_CONCURRENTLY_CONFIRMED;
                         }
-                    } else {
-                        //to_tag parameter does not exist so break
-                        break;
                     }
+                    break;
                 case DLG_STATE_CONCURRENTLY_CONFIRMED:
-
                     //check the to_tag passed parameter exists
-
                     if (to_tag) {
-
                         //compare the to_tag passed parameter to all the dlg_out to_tag entry of the dlg parameter  (There could be multiple)
                         while (dlg_out) {
-
                             if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
                                 //this parameter matches the existing dlg_out and is therefore a retransmission
                                 found = 1;
@@ -1214,12 +1215,10 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
                             //The parameter does not match so this is another concurrently confirmed call (we would have breaked by now if it matched)
                             dlg->state = DLG_STATE_CONCURRENTLY_CONFIRMED;
                         }
-
                     } else {
                         //to_tag parameter does not exist so break
                         break;
                     }
-
                     break;
                 default:
                     log_next_state_dlg(event, dlg);
@@ -1227,6 +1226,9 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
             break;
         case DLG_EVENT_REQACK:
             switch (dlg->state) {
+                case DLG_STATE_CONFIRMED_NA:
+                    dlg->state = DLG_STATE_CONFIRMED;
+                    break;
                 case DLG_STATE_CONFIRMED:
                     break;
                 case DLG_STATE_DELETED:
@@ -1249,6 +1251,8 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
                     log_next_state_dlg(event, dlg);
             }
             break;
+
+            break;
         case DLG_EVENT_REQPRACK:
             switch (dlg->state) {
                 case DLG_STATE_EARLY:
@@ -1276,6 +1280,13 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
                     dlg->from_tag.len, dlg->from_tag.s);
     }
     *new_state = dlg->state;
+    
+    /* remove the dialog from profiles when is not no longer active */
+    if (*new_state == DLG_STATE_DELETED && dlg->profile_links != NULL
+            && *old_state != *new_state) {
+        destroy_linkers(dlg->profile_links);
+        dlg->profile_links = NULL;
+    }
 
     dlg_unlock(d_table, d_entry);
 
@@ -1757,6 +1768,53 @@ error:
     return NULL;
 }
 
+/*!
+ * \brief Search dialog that corresponds to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:
+ * "The combination of the To tag, From tag, and Call-ID completely
+ * defines a peer-to-peer SIP relationship between [two UAs] and is
+ * referred to as a dialog."
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * If the dialog is not found, the hash slot is left locked, to allow
+ * linking the structure of a new dialog.
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure (and slot locked)
+ */
+dlg_cell_t* search_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
+{
+	struct dlg_cell *dlg;
+	unsigned int he;
+
+	he = core_hash(callid, 0, d_table->size);
+	dlg = internal_get_dlg(he, callid, ftag, ttag, dir, 1);
+
+	if (dlg == 0) {
+		LM_DBG("dialog with callid='%.*s' not found\n", callid->len, callid->s);
+		return 0;
+	}
+	return dlg;
+}
+
+/*!
+ * \brief Release hash table slot by call-id
+ * \param callid call-id value
+ */
+void dlg_hash_release(str *callid)
+{
+	unsigned int he;
+	struct dlg_entry *d_entry;
+
+	he = core_hash(callid, 0, d_table->size);
+	d_entry = &(d_table->entries[he]);
+	dlg_unlock(d_table, d_entry);
+}
+
 /*!
  * \brief decrement dialog ref counter by 1
  * \see dlg_unref
@@ -1810,3 +1868,22 @@ char* state_to_char(unsigned int state) {
 		return "Unknown";
 	}
 }
+
+/*!
+ * \brief Search a dialog in the global list by iuid
+ *
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * \param diuid internal unique id per dialog
+ * \return dialog structure on success, NULL on failure
+ */
+dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid)
+{
+	if(diuid==NULL)
+		return NULL;
+	if(diuid->h_id==0)
+		return NULL;
+	/* dlg ref counter is increased by next line */
+	return lookup_dlg(diuid->h_entry, diuid->h_id);
+}
+

+ 66 - 18
modules/dialog_ng/dlg_hash.h

@@ -55,8 +55,9 @@
 #define DLG_STATE_UNCONFIRMED  1 /*!< unconfirmed dialog */
 #define DLG_STATE_EARLY        2 /*!< early dialog */
 #define DLG_STATE_CONFIRMED    4 /*!< confirmed dialog */
-#define DLG_STATE_DELETED      5 /*!< deleted dialog */
-#define DLG_STATE_CONCURRENTLY_CONFIRMED      6 /*!< confirmed concurrent dailogs */
+#define DLG_STATE_CONFIRMED_NA 5 /*!< confirmed dialog without a ACK yet */
+#define DLG_STATE_DELETED      6 /*!< deleted dialog */
+#define DLG_STATE_CONCURRENTLY_CONFIRMED      7 /*!< confirmed concurrent dailogs */
 
 /* events for dialog processing */
 #define DLG_EVENT_TDEL         1 /*!< transaction was destroyed */
@@ -66,7 +67,8 @@
 #define DLG_EVENT_REQPRACK     5 /*!< PRACK request */
 #define DLG_EVENT_REQACK       6 /*!< ACK request */
 #define DLG_EVENT_REQBYE       7 /*!< BYE request */
-#define DLG_EVENT_REQ          8 /*!< other requests */
+#define DLG_EVENT_REQCANCEL    8 /*!< CANCEL request */
+#define DLG_EVENT_REQ          9 /*!< other requests */
 
 /* dialog flags */
 #define DLG_FLAG_NEW           (1<<0) /*!< new dialog */
@@ -77,10 +79,14 @@
 #define DLG_FLAG_CALLEEBYE     (1<<5) /*!< bye from callee */
 #define DLG_FLAG_LOCALDLG      (1<<6) /*!< local dialog, unused */
 #define DLG_FLAG_CHANGED_VARS  (1<<7) /*!< dialog-variables changed */
+#define DLG_FLAG_HASCANCEL     (1<<8) /*!< cancel was received */
 
 /* dialog-variable flags (in addition to dialog-flags) */
-#define DLG_FLAG_DEL           (1<<8) /*!< delete this var */
-#define DLG_FLAG_INSERTED      (1<<9) /*!< DLG already written to DB - could have been put in by early media or confirmed */
+#define DLG_FLAG_DEL           (1<<9) /*!< delete this var */
+#define DLG_FLAG_INSERTED      (1<<10) /*!< DLG already written to DB - could have been put in by early media or confirmed */
+#define DLG_FLAG_TM            (1<<11) /*!< dialog is set in transaction */
+#define DLG_FLAG_EXPIRED       (1<<12)/*!< dialog is expired */
+
 
 #define DLG_CALLER_LEG         0 /*!< attribute that belongs to a caller leg */
 #define DLG_CALLEE_LEG         1 /*!< attribute that belongs to a callee leg */
@@ -89,6 +95,12 @@
 #define DLG_DIR_DOWNSTREAM     1 /*!< dialog has downstream direction */
 #define DLG_DIR_UPSTREAM       2 /*!< dialog has upstream direction */
 
+/*! internal unique ide per dialog */
+typedef struct dlg_iuid {
+	unsigned int         h_id;		/*!< id in the hash table entry (seq nr in slot) */
+	unsigned int         h_entry;           /*!< index of hash table entry (the slot number) */
+} dlg_iuid_t;
+
 /*! entries in the main dialog table */
 struct dlg_entry_out {
     struct dlg_cell_out *first; /*!< dialog list */
@@ -97,7 +109,7 @@ struct dlg_entry_out {
 };
 
 /*! entries in the dialog list */
-struct dlg_cell {
+typedef struct dlg_cell {
     volatile int ref; /*!< reference counter */
     struct dlg_cell *next; /*!< next entry in the list */
     struct dlg_cell *prev; /*!< previous entry in the list */
@@ -127,13 +139,14 @@ struct dlg_cell {
     struct cell *transaction; /*!< ptr to associated transaction for this dialog TM module cell ptr */
     gen_lock_t *dlg_out_entries_lock; /*!< lock for dialog_out linked list */
     unsigned int from_rr_nb; /*!< information from record routing */
-};
+} dlg_cell_t;
 
 struct dlg_cell_out {
     struct dlg_cell_out *next; /*!< next entry in the list */
     struct dlg_cell_out *prev; /*!< previous entry in the list */
     unsigned int h_id; /*!< id of the hash table entry */
     unsigned int h_entry; /*!< number of hash entry */
+    str branch;
     str did;
     str to_uri; /*!< to uri */
     str to_tag; /*!< to tags of callee*/
@@ -147,27 +160,24 @@ struct dlg_cell_out {
 };
 
 /*! entries in the main dialog table */
-struct dlg_entry {
+typedef struct dlg_entry {
     struct dlg_cell *first; /*!< dialog list */
     struct dlg_cell *last; /*!< optimisation, end of the dialog list */
     unsigned int next_id; /*!< next id */
     unsigned int lock_idx; /*!< lock index */
-};
+} dlg_entry_t;
 
 /*! main dialog table */
-struct dlg_table {
+typedef struct dlg_table {
     unsigned int size; /*!< size of the dialog table */
     struct dlg_entry *entries; /*!< dialog hash table */
     unsigned int locks_no; /*!< number of locks */
     gen_lock_set_t *locks; /*!< lock table */
-};
+} dlg_table_t;
 
 
 /*! global dialog table */
 extern struct dlg_table *d_table;
-/*! point to the current dialog */
-extern struct dlg_cell *current_dlg_pointer;
-
 
 /*!
  * \brief Set a dialog lock
@@ -286,6 +296,15 @@ int dlg_update_contact(struct dlg_cell * dlg, unsigned int leg, str *contact, st
  */
 int dlg_set_toroute(struct dlg_cell *dlg, str *route);
 
+/*!
+ * \brief Search and return dialog in the global list by iuid
+ *
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * \param diuid internal unique id per dialog
+ * \return dialog structure on success, NULL on failure
+ */
+dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid);
 
 /*!
  * \brief Lookup a dialog in the global list
@@ -298,6 +317,31 @@ int dlg_set_toroute(struct dlg_cell *dlg, str *route);
  */
 struct dlg_cell* lookup_dlg(unsigned int h_entry, unsigned int h_id);
 
+/*!
+ * \brief Search dialog that corresponds to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:
+ * "The combination of the To tag, From tag, and Call-ID completely
+ * defines a peer-to-peer SIP relationship between [two UAs] and is
+ * referred to as a dialog."
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * If the dialog is not found, the hash slot is left locked, to allow
+ * linking the structure of a new dialog.
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure (and slot locked)
+ */
+dlg_cell_t* search_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
+
+/*!
+ * \brief Release hash table slot by call-id
+ * \param callid call-id value
+ */
+void dlg_hash_release(str *callid);
 
 /*!
  * \brief Get dialog that correspond to CallId, From Tag and To Tag
@@ -322,8 +366,9 @@ struct dlg_cell* get_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
  * \brief Link a dialog structure
  * \param dlg dialog
  * \param n extra increments for the reference counter
+ * \param mode link in safe mode (0 - lock slot; 1 - don't)
  */
-void link_dlg(struct dlg_cell *dlg, int n);
+void link_dlg(struct dlg_cell *dlg, int n, int mode);
 
 
 void link_dlg_out(struct dlg_cell *dlg, struct dlg_cell_out *dlg_out, int n);
@@ -406,6 +451,7 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
 
     if (d_entry_out->first == 0) {
         //there are no dialog out entries yet
+        LM_DBG("No dlg outs yet...\n");
         if (*dir == DLG_DIR_DOWNSTREAM) {
             if (dlg->callid.len == callid->len &&
                     dlg->from_tag.len == ftag->len &&
@@ -441,14 +487,14 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
             LM_DBG("No match found\n");
         }
     } else {
-
+        LM_DBG("searching dlg_outs\n");
         //there is a dialog out entry
         if (*dir == DLG_DIR_DOWNSTREAM) {
             if (dlg->callid.len == callid->len &&
                     dlg->from_tag.len == ftag->len &&
                     strncmp(dlg->callid.s, callid->s, callid->len) == 0 &&
                     strncmp(dlg->from_tag.s, ftag->s, ftag->len) == 0) {
-                //now need to scroll thought d_out_entries to see if to_tag matches!
+                //now need to scroll through d_out_entries to see if to_tag matches!
                 dlg_out = d_entry_out->first;
                 while (dlg_out) {
                     if (dlg_out->to_tag.len == ttag->len &&
@@ -511,6 +557,8 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
                     }
                     dlg_out = dlg_out->next;
                 }
+                *dir = DLG_DIR_UPSTREAM;
+                return 1;
             }
             else
             	LM_DBG("no match tags: ");
@@ -561,7 +609,7 @@ int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context);
  * \return created dlg_out structure on success, NULL otherwise
  */
 
-struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str *to_uri, str* to_tag);
+struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str *to_uri, str* to_tag, str* branch);
 
 /*!
  * \brief Remove all dlg_out entries from dlg structure expect that identified as dlg_do_not_remove

+ 103 - 95
modules/dialog_ng/dlg_profile.c

@@ -43,7 +43,7 @@
 #include "dlg_hash.h"
 #include "dlg_handlers.h"
 #include "dlg_profile.h"
-
+#include "dlg_var.h"
 
 /*! size of dialog profile hash */
 #define PROFILE_HASH_SIZE 16
@@ -53,9 +53,7 @@ extern struct tm_binds d_tmb;
 
 /*! global dialog message id */
 static unsigned int            current_dlg_msg_id = 0 ;
-
-/*! global dialog */
-struct dlg_cell                *current_dlg_pointer = NULL ;
+static unsigned int       current_dlg_msg_pid = 0 ;
 
 /*! pending dialog links */
 static struct dlg_profile_link *current_pending_linkers = NULL;
@@ -67,16 +65,8 @@ static struct dlg_profile_table *profiles = NULL;
 static struct dlg_profile_table* new_dlg_profile( str *name,
 		unsigned int size, unsigned int has_value);
 
+static sruid_t _dlg_profile_sruid;
 
-struct dlg_cell *get_current_dlg_pointer(void)
-{
-	return current_dlg_pointer;
-}
-
-void reset_current_dlg_pointer(void)
-{
-	current_dlg_pointer = NULL;
-}
 
 /*!
  * \brief Add profile definitions to the global list
@@ -311,18 +301,26 @@ void destroy_linkers(struct dlg_profile_link *linker)
  */
 int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
 {
-	current_dlg_msg_id = 0;
-	if (current_dlg_pointer) {
-		unref_dlg( current_dlg_pointer, 1);
-		current_dlg_pointer = NULL;
-	}
-	if (current_pending_linkers) {
-		destroy_linkers(current_pending_linkers);
-		current_pending_linkers = NULL;
-	}
+    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) {
+            unref_dlg(dlg, 1);
+        } else {
+            /* dialog didn't make it to tm */
+            unref_dlg(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;
+    /* need to return non-zero - 0 will break the exec of the request */
+    return 1;
 }
 
 
@@ -345,36 +343,6 @@ struct dlg_cell* get_dialog_from_tm(struct cell *t)
     return NULL;
 }
 
-/*!
- * \brief Get the current dialog for a message, if exists
- * \param msg SIP message
- * \return NULL if called in REQUEST_ROUTE, pointer to dialog ctx otherwise
- */
-struct dlg_cell *get_current_dialog(struct sip_msg *msg)
-{
-
-	if (is_route_type(REQUEST_ROUTE|BRANCH_ROUTE)) {
-            LM_DBG("Get Current Dialog: Route type is REQUEST ROUTE or BRANCH ROUTE");
-            LM_DBG("Get Current Dialog: SIP Method - %.*s", msg->first_line.u.request.method.len, msg->first_line.u.request.method.s);
-		/* use the per-process static holder */
-		if (msg->id==current_dlg_msg_id){
-                    LM_DBG("Message Id [%i] equals current dlg msg id [%i] - returning current dlg pointer", msg->id, current_dlg_msg_id);
-                    return current_dlg_pointer;
-                }
-                LM_DBG("Message Id [%i] not equal to current point dlg id [%i] - returning null", msg->id, current_dlg_msg_id);
-		current_dlg_pointer = NULL;
-		current_dlg_msg_id = msg->id;
-		destroy_linkers(current_pending_linkers);
-		current_pending_linkers = NULL;
-		return NULL;
-	} else {
-		/* use current transaction to get dialog */
-            LM_DBG("Route type is not REQUEST ROUTE or brancg route - getting from tm");
-	    return get_dialog_from_tm(d_tmb.t_gett());
-	}
-}
-
-
 /*!
  * \brief Calculate the hash profile from a dialog
  * \see core_hash
@@ -449,34 +417,33 @@ static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *d
  * \param msg SIP message
  * \param dlg dialog cell
  */
-void set_current_dialog(struct sip_msg *msg, struct dlg_cell *dlg)
+void set_current_dialog(sip_msg_t *msg, dlg_cell_t *dlg)
 {
-	struct dlg_profile_link *linker;
-	struct dlg_profile_link *tlinker;
-
-	/* if linkers are not from current request, just discard them */
-	if (msg->id!=current_dlg_msg_id) {
-		current_dlg_msg_id = msg->id;
-		destroy_linkers(current_pending_linkers);
-	} else {
-		/* add the linker, one be 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;
-	current_dlg_pointer = dlg;
-
-	/* do not increase reference counter here, let caller handle it
-	 * (yes, this is somewhat ugly) */
+        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
@@ -486,11 +453,11 @@ void set_current_dialog(struct sip_msg *msg, struct dlg_cell *dlg)
  */
 int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
 {
-	struct dlg_cell *dlg;
-	struct dlg_profile_link *linker;
+	dlg_cell_t *dlg = NULL;
+	dlg_profile_link_t *linker;
 
 	/* get current dialog */
-	dlg = get_current_dialog(msg);
+	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",
@@ -503,12 +470,13 @@ int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *p
 		sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
 	if (linker==NULL) {
 		LM_ERR("no more shm memory\n");
-		return -1;
+		goto error;
 	}
 	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) {
@@ -516,17 +484,37 @@ int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *p
 		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;
 }
 
 
@@ -540,16 +528,21 @@ int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *p
 int unset_dlg_profile(struct sip_msg *msg, str *value,
 		struct dlg_profile_table *profile)
 {
-	struct dlg_cell *dlg;
-	struct dlg_profile_link *linker;
-	struct dlg_profile_link *linker_prev;
-	struct dlg_entry *d_entry;
+	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 = get_current_dialog(msg);
+	dlg = dlg_get_msg_dialog(msg);
 
-	if (dlg==NULL || is_route_type(REQUEST_ROUTE)) {
-		LM_CRIT("BUG - dialog NULL or del_profile used in request route\n");
+	if (dlg==NULL) {
+		LM_WARN("dialog is NULL for delete profile\n");
 		return -1;
 	}
 
@@ -572,6 +565,7 @@ int unset_dlg_profile(struct sip_msg *msg, str *value,
 		}
 	}
 	dlg_unlock( d_table, d_entry);
+	dlg_release(dlg);
 	return -1;
 
 found:
@@ -586,6 +580,7 @@ found:
 	dlg_unlock( d_table, d_entry);
 	/* remove linker from profile table and free it */
 	destroy_linkers(linker);
+	dlg_release(dlg);
 	return 1;
 }
 
@@ -602,10 +597,11 @@ int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
 	struct dlg_cell *dlg;
 	struct dlg_profile_link *linker;
 	struct dlg_entry *d_entry;
+        int ret;
 
 	LM_DBG("Getting current dialog");
 	/* get current dialog */
-	dlg = get_current_dialog(msg);
+	dlg = dlg_get_msg_dialog(msg);
 
 	if (dlg == NULL) {
 		LM_DBG("Error: Current dlg is null");
@@ -614,6 +610,7 @@ int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
 	}
 	LM_DBG("Current dlg found");
 
+        ret = -1;
 	/* check the dialog linkers */
 	d_entry = &d_table->entries[dlg->h_entry];
 	dlg_lock( d_table, d_entry);
@@ -624,13 +621,15 @@ int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
 			if (profile->has_value == 0) {
 				LM_DBG("Profile has value is zero returning true");
 				dlg_unlock( d_table, d_entry);
-				return 1;
+				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) {
 				LM_DBG("Profile has value equal to passed value returning true");
 				dlg_unlock( d_table, d_entry);
-				return 1;
+				ret = 1;
+                                goto done;
 			}
 			/* allow further search - maybe the dialog is inserted twice in
 			 * the same profile, but with different values -bogdan
@@ -638,7 +637,10 @@ int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
 		}
 	}
 	dlg_unlock( d_table, d_entry);
-	return -1;
+        
+done:
+        dlg_release(dlg);
+        return ret;
 }
 
 
@@ -688,9 +690,15 @@ unsigned int get_profile_size(struct dlg_profile_table *profile, str *value)
  * Determine if message is in a dialog currently being tracked
  */
 int	is_known_dlg(struct sip_msg *msg) {
-	if(get_current_dialog(msg) == NULL)
+	dlg_cell_t *dlg;
+
+	dlg = dlg_get_msg_dialog(msg);
+	
+	if(dlg == NULL)
 		return -1;
 
+	dlg_release(dlg);
+
 	return 1;
 }
 

+ 11 - 11
modules/dialog_ng/dlg_profile.h

@@ -34,6 +34,8 @@
 #include "../../locking.h"
 #include "../../str.h"
 #include "../../modules/tm/h_table.h"
+#include "../../lib/srutils/srjson.h"
+#include "../../lib/srutils/sruid.h"
 
 
 
@@ -46,21 +48,26 @@
 
 
 /*! dialog profile hash list */
-struct dlg_profile_hash {
+typedef struct dlg_profile_hash {
 	str value; /*!< hash value */
 	struct dlg_cell *dlg; /*!< dialog cell */
+	char puid[SRUID_SIZE];
+	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 */
-};
+} dlg_profile_hash_t;
 
 
 /*! list with links to dialog profiles */
-struct dlg_profile_link {
+typedef struct dlg_profile_link {
 	struct dlg_profile_hash hash_linker;
 	struct dlg_profile_link  *next;
 	struct dlg_profile_table *profile;
-};
+} dlg_profile_link_t;
 
 
 /*! dialog profile entry */
@@ -80,15 +87,8 @@ struct dlg_profile_table {
 	struct dlg_profile_table *next;
 };
 
-
-struct dlg_cell *get_current_dlg_pointer(void);
-
-void reset_current_dlg_pointer(void);
-
 struct dlg_cell* get_dialog_from_tm(struct cell *t);
 
-struct dlg_cell *get_current_dialog(struct sip_msg *msg);
-
 /*!
  * \brief Add profile definitions to the global list
  * \see new_dlg_profile

+ 2 - 4
modules/dialog_ng/dlg_req_within.c

@@ -94,7 +94,7 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dir) {
     memset(td, 0, sizeof (dlg_t));
 
     if (dir == DLG_CALLER_LEG) {
-        cseq = dlg_out->callee_cseq;
+        cseq = cell->first_req_cseq;
         route_set = cell->caller_route_set;
         contact = cell->caller_contact;
         td->rem_uri = cell->from_uri;
@@ -103,7 +103,7 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dir) {
         td->id.loc_tag = dlg_out->to_tag;
         td->send_sock = cell->caller_bind_addr;
     } else {
-        cseq = dlg_out->caller_cseq;
+        cseq = dlg_out->callee_cseq;
         route_set = dlg_out->callee_route_set;
         contact = dlg_out->callee_contact;
         td->rem_uri = dlg_out->to_uri;
@@ -122,8 +122,6 @@ dlg_t * build_dlg_t(struct dlg_cell * cell, int dir) {
     td->loc_seq.value = loc_seq;
     td->loc_seq.is_set = 1;
 
-    LM_DBG("CSeq is '%.*s' (%i)\n", cseq.len, cseq.s, loc_seq);
-
     /*route set*/
     if (route_set.s && route_set.len) {
 

+ 74 - 35
modules/dialog_ng/dlg_var.c

@@ -22,10 +22,12 @@
  */
 		       
 #include "../../route.h"
+#include "../../pvapi.h"
 
 #include "dlg_var.h"
 #include "dlg_hash.h"
 #include "dlg_profile.h"
+#include "dlg_handlers.h"
 #include "dlg_db_handler.h"
 
 dlg_ctx_t _dlg_ctx;
@@ -103,7 +105,7 @@ struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointe
 }
 
 /* Adds, updates and deletes dialog variables */
-int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val, int new)
+int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val)
 {
 	struct dlg_var * var = NULL;
 	struct dlg_var * it;
@@ -149,10 +151,9 @@ int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val, int new)
 	}
 
 	/* not found: */
-
 	if (!var) {
-		LM_ERR("dialog variable <%.*s> does not exist in variable list\n", key->len, key->s);
-		return -1;
+		LM_DBG("dialog variable <%.*s> does not exist in variable list\n", key->len, key->s);
+		return 1;
 	}
 
 	/* insert a new one at the beginning of the list */
@@ -283,12 +284,12 @@ int set_dlg_variable(struct dlg_cell *dlg, str *key, str *val)
 
     if( !val)
     {
-        if (set_dlg_variable_unsafe(dlg, key, NULL, 1)!=0) {
+        if (set_dlg_variable_unsafe(dlg, key, NULL)!=0) {
             LM_ERR("failed to delete dialog variable <%.*s>\n", key->len,key->s);
             goto error;
         }
     } else {
-        if (set_dlg_variable_unsafe(dlg, key, val, 1)!=0) {
+        if (set_dlg_variable_unsafe(dlg, key, val)!=0) {
             LM_ERR("failed to store dialog values <%.*s>\n",key->len,key->s);
             goto error;
         }
@@ -311,16 +312,20 @@ error:
 
 int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
-	struct dlg_cell *dlg;
+
+	dlg_cell_t *dlg;
 	str * value;
+	str spv;
 
-	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR || param->pvn.u.isname.type!=AVP_NAME_STR || param->pvn.u.isname.name.s.s==NULL) {
+	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
+			|| param->pvn.u.isname.type!=AVP_NAME_STR
+			|| param->pvn.u.isname.name.s.s==NULL) {
 		LM_CRIT("BUG - bad parameters\n");
 		return -1;
 	}
 
-	/* Retrieve the current dialog */
-	dlg=get_current_dialog( msg);
+	/* Retrieve the dialog for current message */
+	dlg=dlg_get_msg_dialog( msg);
 
 	if (dlg) {
 		/* Lock the dialog */
@@ -330,26 +335,51 @@ int pv_get_dlg_variable(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 		get_local_varlist_pointer(msg, 0);
 	}
 
+	/* dcm: todo - the value should be cloned for safe usage */
 	value = get_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s);
 
+	spv.s = NULL;
+	if(value) {
+		spv.len = pv_get_buffer_size();
+		if(spv.len<value->len+1) {
+			LM_ERR("pv buffer too small (%d) - needed %d\n", spv.len, value->len);
+		} else {
+			spv.s = pv_get_buffer();
+			strncpy(spv.s, value->s, value->len);
+			spv.len = value->len;
+			spv.s[spv.len] = '\0';
+		}
+	}
+
 	print_lists(dlg);
 
 	/* unlock dialog */
-	if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+	if (dlg) {
+		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+		dlg_release(dlg);
+	}
 
-	if (value)
-		return pv_get_strval(msg, param, res, value);
+	if (spv.s)
+		return pv_get_strval(msg, param, res, &spv);
 
 
-	return 0;
+	return pv_get_null(msg, param, res);
 }
 
 int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val)
 {
-	struct dlg_cell *dlg;
+	dlg_cell_t *dlg = NULL;
+	int ret = -1;
+
+	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR
+			|| param->pvn.u.isname.type!=AVP_NAME_STR
+			|| param->pvn.u.isname.name.s.s==NULL ) {
+		LM_CRIT("BUG - bad parameters\n");
+		goto error;
+	}
 
-	/* Retrieve the current dialog */
-	dlg=get_current_dialog( msg);
+	/* Retrieve the dialog for current message */
+	dlg=dlg_get_msg_dialog( msg);
 	
 	if (dlg) {
 		/* Lock the dialog */
@@ -359,18 +389,16 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 		get_local_varlist_pointer(msg, 0);
 	}
 
-	if (param==NULL || param->pvn.type!=PV_NAME_INTSTR || param->pvn.u.isname.type!=AVP_NAME_STR || param->pvn.u.isname.name.s.s==NULL ) {
-		LM_CRIT("BUG - bad parameters\n");
-		return -1;
-	}
-
 	if (val==NULL || val->flags&(PV_VAL_NONE|PV_VAL_NULL|PV_VAL_EMPTY)) {
 		/* if NULL, remove the value */
-		if (set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, NULL, 1)!=0) {
-			LM_ERR("failed to delete dialog variable <%.*s>\n", param->pvn.u.isname.name.s.len,param->pvn.u.isname.name.s.s);
+		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, NULL);
+		if(ret!= 0) {
 			/* unlock dialog */
-			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
-			return -1;
+			if (dlg) {
+				dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
+				dlg_release(dlg);
+			}
+			return ret;
 		}
 	} else {
 		/* if value, must be string */
@@ -378,19 +406,19 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 			LM_ERR("non-string values are not supported\n");
 			/* unlock dialog */
 			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
-			return -1;
+			goto error;
 		}
 
-		if (set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, &val->rs, 1)!=0) {
-			LM_ERR("failed to store dialog values <%.*s>\n",param->pvn.u.isname.name.s.len,param->pvn.u.isname.name.s.s);
+		ret = set_dlg_variable_unsafe(dlg, &param->pvn.u.isname.name.s, &val->rs);
+		if(ret!= 0) {
 			/* unlock dialog */
 			if (dlg) dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
-			return -1;
+			goto error;
 		}
 	}
 	/* unlock dialog */
 	if (dlg) {
-		dlg->dflags &= DLG_FLAG_CHANGED_VARS;		
+		dlg->dflags |= DLG_FLAG_CHANGED_VARS;
 		dlg_unlock(d_table, &(d_table->entries[dlg->h_entry]));
 		if ( dlg_db_mode==DB_MODE_REALTIME )
 			update_dialog_dbinfo(dlg);
@@ -398,7 +426,11 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 	}
 	print_lists(dlg);
 
+	dlg_release(dlg);
 	return 0;
+error:
+	dlg_release(dlg);
+	return -1;
 }
 
 int pv_get_dlg_ctx(struct sip_msg *msg,  pv_param_t *param,
@@ -749,14 +781,21 @@ error:
 	return -1;
 }
 
-void dlg_set_ctx_dialog(struct dlg_cell *dlg)
+void dlg_set_ctx_iuid(dlg_cell_t *dlg)
+{
+	_dlg_ctx.iuid.h_entry = dlg->h_entry;
+	_dlg_ctx.iuid.h_id = dlg->h_id;
+}
+
+void dlg_reset_ctx_iuid(void)
 {
-	_dlg_ctx.dlg = dlg;
+	_dlg_ctx.iuid.h_entry = 0;
+	_dlg_ctx.iuid.h_id = 0;
 }
 
-struct dlg_cell* dlg_get_ctx_dialog(void)
+dlg_cell_t* dlg_get_ctx_dialog(void)
 {
-	return _dlg_ctx.dlg;
+	return dlg_get_by_iuid(&_dlg_ctx.iuid);
 }
 
 dlg_ctx_t* dlg_get_dlg_ctx(void)

+ 27 - 21
modules/dialog_ng/dlg_var.h

@@ -30,23 +30,28 @@
 #define DLG_TOROUTE_SIZE	32
 /*! dialog context */
 typedef struct _dlg_ctx {
-	int on;
-	unsigned int flags;
-	int to_route;
-	char to_route_name[DLG_TOROUTE_SIZE];
-	int to_bye;
-	int timeout;
-	struct dlg_cell *dlg;
-	int set;
-	unsigned int dir;
+    int on;
+    unsigned int flags;
+    unsigned int iflags;
+    int to_route;
+    char to_route_name[DLG_TOROUTE_SIZE];
+    int to_bye;
+    int timeout;
+    struct dlg_cell *dlg;
+    dlg_iuid_t iuid;
+    int cpid;
+    int set;
+    unsigned int dir;
+    int t; /* set to 1 if tm req in callback executed */
+    int expect_t; /* set to 1 if expects that t is set after config */
 } dlg_ctx_t;
 
 /* A dialog-variable */
 struct dlg_var {
-	str key;
-	str value;
-	unsigned int vflags;		/*!< internal variable flags */
-	struct dlg_var *next;
+    str key;
+    str value;
+    unsigned int vflags; /*!< internal variable flags */
+    struct dlg_var *next;
 };
 
 str * api_get_dlg_variable(str *callid, str *ftag, str *ttag, str *key);
@@ -65,24 +70,25 @@ int pv_set_dlg_variable(struct sip_msg* msg, pv_param_t *param, int op, pv_value
 struct dlg_var * get_local_varlist_pointer(struct sip_msg *msg, int clear_pointer);
 
 /* Adds, updates and deletes dialog variables */
-int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val, int new);
+int set_dlg_variable_unsafe(struct dlg_cell *dlg, str *key, str *val);
 
 extern dlg_ctx_t _dlg_ctx;
 
-int pv_get_dlg_ctx(struct sip_msg *msg,  pv_param_t *param,
-		pv_value_t *res);
+int pv_get_dlg_ctx(struct sip_msg *msg, pv_param_t *param,
+        pv_value_t *res);
 int pv_set_dlg_ctx(struct sip_msg* msg, pv_param_t *param,
-		int op, pv_value_t *val);
+        int op, pv_value_t *val);
 int pv_parse_dlg_ctx_name(pv_spec_p sp, str *in);
 
-int pv_get_dlg(struct sip_msg *msg,  pv_param_t *param,
-		pv_value_t *res);
+int pv_get_dlg(struct sip_msg *msg, pv_param_t *param,
+        pv_value_t *res);
 int pv_parse_dlg_name(pv_spec_p sp, str *in);
 
 int dlg_cfg_cb(struct sip_msg *foo, unsigned int flags, void *bar);
 
-void dlg_set_ctx_dialog(struct dlg_cell *dlg);
-struct dlg_cell* dlg_get_ctx_dialog(void);
+void dlg_set_ctx_iuid(dlg_cell_t *dlg);
+void dlg_reset_ctx_iuid(void);
+dlg_cell_t* dlg_get_ctx_dialog(void);
 
 dlg_ctx_t* dlg_get_dlg_ctx(void);
 

+ 1 - 0
modules/ims_charging/Makefile

@@ -14,6 +14,7 @@ SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/kcore/kcore
 SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+LIBS+=-lm
 
 ifneq ($(OS),darwin)
 	LIBS += -lrt

+ 1 - 1
modules/ims_charging/Ro_data.c

@@ -124,7 +124,7 @@ ims_information_t * new_ims_information(event_type_t * event_type, time_stamps_t
     if (outgoing_trunk_id && outgoing_trunk_id->s)
         str_dup_ptr(x->outgoing_trunk_id, *outgoing_trunk_id, pkg);
     
-    if (pani && pani->s) {
+    if (pani && pani->s && (pani->len > 0)) {
 	str_dup_ptr(x->access_network_info, *pani, pkg);
     }
 

+ 100 - 88
modules/ims_charging/dialog.c

@@ -10,97 +10,108 @@ struct cdp_binds cdpb;
 extern usrloc_api_t ul;
 extern int ro_db_mode;
 extern char *domain;
+extern struct dlg_binds dlgb;
 
-void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
-	struct sip_msg *reply;
-	struct ro_session* session = 0;
-	struct ro_session_entry* ro_session_entry;
-	time_t now = time(0);
-	time_t time_since_last_event;
+void dlg_callback_received(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
+    LM_DBG("Received dialog callback event [%d]\n", type);
+    switch (type) {
+        case DLGCB_CONFIRMED:
+            dlg_answered(dlg, type, _params);
+            break;
+        case DLGCB_TERMINATED:
+        case DLGCB_FAILED:
+        case DLGCB_EXPIRED:
+            dlg_terminated(dlg, type, _params);
+            break;
+        default:
+            LM_WARN("Received unknown dialog callback [%d]\n", type);
+    }
+}
 
-	LM_DBG("dlg_reply callback entered\n");
-	
-	if (!_params) {
-		return;
-	}
-	
-	reply = _params->rpl;
-	if (!reply) {
-		LM_WARN("dlg_reply has no SIP reply associated.\n");
-		return;
-	}
+void dlg_answered(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
+    struct sip_msg *reply;
+    struct ro_session* session = 0;
+    struct ro_session_entry* ro_session_entry;
+    time_t now = get_current_time_micro();
+    time_t time_since_last_event;
 
-	if (reply != FAKED_REPLY && reply->REPLY_STATUS == 200) {
-		LM_DBG("Call answered on dlg [%p] - search for Ro Session and initialise timers.\n", dlg);
-		
-		session = (struct ro_session*)*_params->param;
-		if (!session) {
-			LM_ERR("Ro Session object is NULL...... aborting\n");
-			return;
-		}
+    LM_DBG("dlg_reply callback entered\n");
 
-		ro_session_entry = &(ro_session_table->entries[session->h_entry]);
+    if (!_params) {
+        return;
+    }
 
-		ro_session_lock(ro_session_table, ro_session_entry);
+    session = (struct ro_session*) *_params->param;
+    if (!session) {
+        LM_ERR("Ro Session object is NULL...... aborting\n");
+        return;
+    }
+    
+    LM_DBG("Call answered on dlg [%p] - search for Ro Session [%p]\n", dlg, session);
 
-		if (session->active) {
-			LM_CRIT("Why the heck am i receiving a double confirmation of the dialog? Ignoring... ");
-			ro_session_unlock(ro_session_table, ro_session_entry);
-			return;
-		}
-	
-		time_since_last_event = now - session->last_event_timestamp;
-		session->start_time = session->last_event_timestamp = now;
-		session->event_type = answered;
-		session->active = 1;
-		
+    ro_session_entry = &(ro_session_table->entries[session->h_entry]);
 
-		/* check to make sure that the validity of the credit is enough for the bundle */
-		int ret = 0;
-		if (session->reserved_secs < (session->valid_for - time_since_last_event)) {
-			if (session->reserved_secs > ro_timer_buffer/*TIMEOUTBUFFER*/) {
-				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
-			} else {
-				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs);
-			}
-		} else {
-			if (session->valid_for > ro_timer_buffer) {
-				ret = insert_ro_timer(&session->ro_tl, session->valid_for - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
-			} else {
-				ret = insert_ro_timer(&session->ro_tl, session->valid_for);
-			}
-		}
+    ro_session_lock(ro_session_table, ro_session_entry);
 
+    if (session->active) {
+        LM_CRIT("Why the heck am i receiving a double confirmation of the dialog? Ignoring... ");
+        ro_session_unlock(ro_session_table, ro_session_entry);
+        return;
+    } else if (session->active < 0) {   //session has already been terminated - we can't reactivate...
+        LM_WARN("Received an answer after terminating dialog.... ignoring\n");
+        ro_session_unlock(ro_session_table, ro_session_entry);
+        return;
+    }
 
-		if (ret != 0) {
-			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s); 
-		} else {
-			ref_ro_session_unsafe(session, 1); // lock already acquired
-		}
+    time_since_last_event = (now - session->last_event_timestamp)/1000000;
+    session->start_time = session->last_event_timestamp = now;
+    session->event_type = answered;
+    session->active = 1;
 
-		if (ro_db_mode == DB_MODE_REALTIME) {
-		    session->flags |= RO_SESSION_FLAG_CHANGED;
-		    if (update_ro_dbinfo_unsafe(session) != 0) {
-			LM_ERR("Failed to update ro_session in database... continuing\n");
-		    };
-		}
-				
-		ro_session_unlock(ro_session_table, ro_session_entry);
 
-		AAASession* cdp_session = cdpb.AAAGetCCAccSession(session->ro_session_id);
-		if (!cdp_session) {
-			LM_ERR("could not find find CC App CDP session for session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
-//			ro_session_unlock(ro_session_table, ro_session_entry);
-			return;
-		}
-		
-//		ro_session_unlock(ro_session_table, ro_session_entry);
+    /* check to make sure that the validity of the credit is enough for the bundle */
+    int ret = 0;
+    LM_DBG("we were granted %d seconds (valud for %d seconds) and it's been %d seconds since we requested\n", (int)session->reserved_secs, (int)session->valid_for, (int)time_since_last_event);
+    if (session->reserved_secs < (session->valid_for - time_since_last_event)) {
+        if (session->reserved_secs > ro_timer_buffer/*TIMEOUTBUFFER*/) {
+            ret = insert_ro_timer(&session->ro_tl, session->reserved_secs - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
+        } else {
+            ret = insert_ro_timer(&session->ro_tl, session->reserved_secs);
+        }
+    } else {
+        if (session->valid_for > ro_timer_buffer) {
+            ret = insert_ro_timer(&session->ro_tl, session->valid_for - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
+        } else {
+            ret = insert_ro_timer(&session->ro_tl, session->valid_for);
+        }
+    }
+
+
+    if (ret != 0) {
+        LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
+    } else {
+        ref_ro_session_unsafe(session, 1); // lock already acquired
+    }
+
+    if (ro_db_mode == DB_MODE_REALTIME) {
+        session->flags |= RO_SESSION_FLAG_CHANGED;
+        if (update_ro_dbinfo_unsafe(session) != 0) {
+            LM_ERR("Failed to update ro_session in database... continuing\n");
+        };
+    }
+
+    ro_session_unlock(ro_session_table, ro_session_entry);
+
+    AAASession* cdp_session = cdpb.AAAGetCCAccSession(session->ro_session_id);
+    if (!cdp_session) {
+        LM_ERR("could not find find CC App CDP session for session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
+        return;
+    }
+
+    cdpb.AAAStartChargingCCAccSession(cdp_session);
+    cdpb.AAASessionsUnlock(cdp_session->hash);
+
 
-		cdpb.AAAStartChargingCCAccSession(cdp_session);
-		cdpb.AAASessionsUnlock(cdp_session->hash);		
-		
-//		unref_ro_session(session, 1);	DONT need this anymore because we don't do lookup so no addition to ref counter
-	}
 }
 
 void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
@@ -155,20 +166,18 @@ void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_param
 					int ret = remove_ro_timer(&ro_session->ro_tl);
 					if (ret < 0) {
 						LM_CRIT("unable to unlink the timer on ro_session %p [%.*s]\n", 
-							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);
+							ro_session, ro_session->ro_session_id.len, ro_session->ro_session_id.s);
 					} else if (ret > 0) {
 						LM_WARN("inconsistent ro timer data on ro_session %p [%.*s]\n",
-							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);						
+							ro_session, ro_session->ro_session_id.len, ro_session->ro_session_id.s);						
 					} else {
 						unref++;
 					}
 				}
 
-				if (ro_session->event_type != unknown) {
-					LM_DBG("Sending CCR STOP on Ro_Session [%p], as it is in '%d' state\n", ro_session, ro_session->event_type);
-					send_ccr_stop(ro_session);
-					ro_session->active = 0;
-				}
+				LM_DBG("Sending CCR STOP on Ro_Session [%p]\n", ro_session);
+				send_ccr_stop(ro_session);
+				ro_session->active = -1;    //deleted.... terminated ....
 				
 				if (ro_db_mode == DB_MODE_REALTIME) {
 				    ro_session->flags |= RO_SESSION_FLAG_DELETED;
@@ -216,7 +225,7 @@ void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_
 	if (ul.get_impurecord(domain_t, &impu_data->identity, &implicit_impurecord) != 0) {
 	    LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n");
 	}else {
-	    if (ul.get_ucontact(implicit_impurecord, &impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
+	    if (ul.get_ucontact(&impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
 		LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_PORT_IP_ONLY\n", impu_data->contact.len, impu_data->contact.s);
 	    } else {//contact exists so add dialog data to it
 		ul.remove_dialog_data_from_contact(ucontact, dlg->h_entry, dlg->h_id);
@@ -226,6 +235,9 @@ void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_
 	ul.unlock_udomain(domain_t, &impu_data->identity);
 	free_impu_data(impu_data);
     }
+    
+    //we referenced the dialog when we registered for callbacks on it...
+    dlgb.release_dlg(dlg);
 }
 
 void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
@@ -258,7 +270,7 @@ void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_param
 	if (ul.get_impurecord(domain_t, &impu_data->identity, &implicit_impurecord) != 0) {
 	    LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n");
 	}else {
-	    if (ul.get_ucontact(implicit_impurecord, &impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
+	    if (ul.get_ucontact(&impu_data->contact, &callid, &path, 0/*cseq*/,  &ucontact) != 0) { //contact does not exist
 		LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_PORT_IP_ONLY\n", impu_data->contact.len, impu_data->contact.s);
 	    } else {//contact exists so add dialog data to it
 		ul.add_dialog_data_to_contact(ucontact, dlg->h_entry, dlg->h_id);

+ 2 - 1
modules/ims_charging/dialog.h

@@ -8,8 +8,9 @@
 
 extern int ro_timer_buffer;
 
+void dlg_callback_received(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
 void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
-void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
+void dlg_answered(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
 void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
 void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params);
 

文件差异内容过多而无法显示
+ 286 - 286
modules/ims_charging/ims_ro.c


+ 2 - 0
modules/ims_charging/ims_ro.h

@@ -3,6 +3,7 @@
 
 #include "../../mod_fix.h"
 #include "../cdp/diameter_api.h"
+#include "../dialog_ng/dlg_hash.h"
 #include "ro_session_hash.h"
 
 struct interim_ccr {
@@ -16,6 +17,7 @@ void credit_control_session_callback(int event, void* session);
 void remove_aaa_session(str *session_id);
 int Ro_Send_CCR(struct sip_msg *msg, struct dlg_cell *dlg, int dir, int reservation_units, 
 	    str *incoming_trunk_id, str *outgoing_trunk_id, str *enb_cell_id, cfg_action_t* action, unsigned int tindex, unsigned int tlabel);
+long get_current_time_micro();
 void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned int reserve);
 void send_ccr_stop(struct ro_session *ro_session);
 int get_direction_as_int(str* direction);

+ 11 - 30
modules/ims_charging/mod.c

@@ -172,7 +172,6 @@ int fix_parameters() {
 
 static int mod_init(void) {
 	int n;
-	load_dlg_f load_dlg;
 	load_tm_f load_tm;
 	bind_usrloc_t bind_usrloc;
 
@@ -189,13 +188,6 @@ static int mod_init(void) {
 	if (load_tm(&tmb) == -1)
 		goto error;
 
-	if (!(load_dlg = (load_dlg_f) find_export("load_dlg", 0, 0))) { /* bind to dialog module */
-		LM_ERR("can not import load_dlg. This module requires Kamailio dialog module.\n");
-	}
-	if (load_dlg(&dlgb) == -1) {
-		goto error;
-	}
-
 	if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */
 		LM_ERR("can't load CDP API\n");
 		goto error;
@@ -211,6 +203,16 @@ static int mod_init(void) {
 		LM_ERR("can't load CDP_AVP API\n");
 		goto error;
 	}
+        
+        bind_usrloc = (bind_usrloc_t) find_export("ul_bind_usrloc", 1, 0);
+	if (!bind_usrloc) {
+	    LM_ERR("can't bind usrloc\n");
+	    return -1;
+	}
+	
+	if (bind_usrloc(&ul) < 0) {
+	    return -1;
+	}
 
 	/* init timer lists*/
 	if (init_ro_timer(ro_session_ontimeout) != 0) {
@@ -239,15 +241,7 @@ static int mod_init(void) {
 		return -1;
 	}
 
-	bind_usrloc = (bind_usrloc_t) find_export("ul_bind_usrloc", 1, 0);
-	if (!bind_usrloc) {
-	    LM_ERR("can't bind usrloc\n");
-	    return -1;
-	}
 	
-	if (bind_usrloc(&ul) < 0) {
-	    return -1;
-	}
 
 	/*Register for callback of URECORD being deleted - so we can send a SAR*/
 
@@ -491,21 +485,7 @@ static int w_ro_ccr(struct sip_msg *msg, char* c_route_name, char* c_direction,
 	    ret = RO_RETURN_ERROR;
 	    goto done;
 	}
-	
-	
-	//reg for callbacks on confirmed and terminated
-	if (dlgb.register_dlgcb(dlg, /* DLGCB_RESPONSE_FWDED */ DLGCB_CONFIRMED, add_dlg_data_to_contact, (void*)impu_data ,NULL ) != 0) {
-	    LM_CRIT("cannot register callback for dialog confirmation\n");
-	    ret = RO_RETURN_ERROR;
-	    goto done;
-	}
 
-	if (dlgb.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED /*| DLGCB_DESTROY */, remove_dlg_data_from_contact, (void*)impu_data, NULL ) != 0) {
-	    LM_CRIT("cannot register callback for dialog termination\n");
-	    ret = RO_RETURN_ERROR;
-	    goto done;
-	}
-	
 send_ccr:
 
 	//check if we need to send_ccr - 
@@ -565,6 +545,7 @@ send_ccr:
     
 done:
 	if(free_contact)  shm_free(contact.s);// shm_malloc in cscf_get_public_identity_from_requri	
+        dlgb.release_dlg(dlg);
 	return ret;
 }
 

+ 4 - 4
modules/ims_charging/ro_db_handler.c

@@ -180,8 +180,8 @@ int update_ro_dbinfo_unsafe(struct ro_session* ro_session) {
 	db_set_int_val(values, DIRECTION_COL_IDX, ro_session->direction);
 	db_set_str_val(values, ASSERTED_ID_COL_IDX, &ro_session->asserted_identity);
 	db_set_str_val(values, CALLEE_COL_IDX, &ro_session->called_asserted_identity);
-	db_set_datetime_val(values, START_TIME_COL_IDX, ro_session->start_time);
-	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX, ro_session->last_event_timestamp);
+	db_set_datetime_val(values, START_TIME_COL_IDX, ro_session->start_time/1000000);
+	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX, ro_session->last_event_timestamp/1000000);
 	db_set_int_val(values, RESERVED_SECS_COL_IDX, ro_session->reserved_secs);
 	db_set_int_val(values, VALID_FOR_COL_IDX, ro_session->valid_for);
 	db_set_int_val(values, STATE_COL_IDX, ro_session->active);
@@ -216,8 +216,8 @@ int update_ro_dbinfo_unsafe(struct ro_session* ro_session) {
 	db_set_int_val(values, DIRECTION_COL_IDX - 1, ro_session->direction);
 	db_set_str_val(values, ASSERTED_ID_COL_IDX - 1, &ro_session->asserted_identity);
 	db_set_str_val(values, CALLEE_COL_IDX - 1, &ro_session->called_asserted_identity);
-	db_set_datetime_val(values, START_TIME_COL_IDX - 1, ro_session->start_time);
-	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX - 1, ro_session->last_event_timestamp);
+	db_set_datetime_val(values, START_TIME_COL_IDX - 1, ro_session->start_time/1000000);
+	db_set_datetime_val(values, LAST_EVENT_TS_COL_IDX - 1, ro_session->last_event_timestamp/1000000);
 	db_set_int_val(values, RESERVED_SECS_COL_IDX - 1, ro_session->reserved_secs);
 	db_set_int_val(values, VALID_FOR_COL_IDX - 1, ro_session->valid_for);
 	db_set_int_val(values, STATE_COL_IDX - 1, ro_session->active);

+ 16 - 10
modules/ims_charging/ro_session_hash.c

@@ -6,6 +6,7 @@
  */
 
 #include "ro_session_hash.h"
+#include "ims_ro.h"
 
 #define MAX_ROSESSION_LOCKS  2048
 #define MIN_ROSESSION_LOCKS  2
@@ -20,6 +21,8 @@ struct ro_session_table *ro_session_table = 0;
  */
 void link_ro_session(struct ro_session *ro_session, int n) {
     struct ro_session_entry *ro_session_entry;
+    
+    LM_DBG("Linking Ro session [%.*s] into entries hash index [%d]", ro_session->ro_session_id.len, ro_session->ro_session_id.s, ro_session->h_entry);
 
     ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
 
@@ -126,6 +129,15 @@ error0:
     return -1;
 }
 
+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;
+}
+
 /*!
  * \brief Destroy an ro_session and free memory
  * \param ro_session destroyed Ro Session
@@ -140,7 +152,6 @@ inline void destroy_ro_session(struct ro_session *ro_session) {
         shm_free(ro_session->ro_session_id.s);
     }
 
-
     shm_free(ro_session);
 }
 
@@ -180,7 +191,7 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
 	int active_rating_group, int active_service_identifier, str *incoming_trunk_id, str *outgoing_trunk_id, str *pani){
     LM_DBG("Building Ro Session **********");
     char *p;
-    unsigned int len = session_id->len + callid->len + asserted_identity->len + called_asserted_identity->len + mac->len + 
+    unsigned int len = /*session_id->len + */callid->len + asserted_identity->len + called_asserted_identity->len + mac->len + 
         incoming_trunk_id->len + outgoing_trunk_id->len + pani->len + sizeof (struct ro_session);
     struct ro_session *new_ro_session = (struct ro_session*) shm_malloc(len);
 
@@ -203,7 +214,7 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
     new_ro_session->auth_appid = auth_appid;
     new_ro_session->auth_session_type = auth_session_type;
 
-    new_ro_session->ro_tl.next = new_ro_session->ro_tl.prev;
+    new_ro_session->ro_tl.next = new_ro_session->ro_tl.prev;// = 0;
     new_ro_session->ro_tl.timeout = 0; //requested_secs;
 
     new_ro_session->reserved_secs = requested_secs;
@@ -227,11 +238,6 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
     memcpy(p, callid->s, callid->len);
     p += callid->len;
 
-    new_ro_session->ro_session_id.s = p;
-    new_ro_session->ro_session_id.len = session_id->len;
-    memcpy(p, session_id->s, session_id->len);
-    p += session_id->len;
-
     new_ro_session->asserted_identity.s = p;
     new_ro_session->asserted_identity.len = asserted_identity->len;
     memcpy(p, asserted_identity->s, asserted_identity->len);
@@ -252,8 +258,8 @@ struct ro_session* build_new_ro_session(int direction, int auth_appid, int auth_
     memcpy(p, outgoing_trunk_id->s, outgoing_trunk_id->len);
     p += outgoing_trunk_id->len;
     
-    new_ro_session->avp_value.mac.s = p;
-    new_ro_session->avp_value.mac.len = mac->len;
+    new_ro_session->mac.s = p;
+    new_ro_session->mac.len = mac->len;
     memcpy(p, mac->s, mac->len);
     p += mac->len;
     

+ 11 - 10
modules/ims_charging/ro_session_hash.h

@@ -23,26 +23,25 @@
 #define MAX_PANI_LEN 100
 
 enum ro_session_event_type {
-    unknown = 0,
     pending,
     answered,
     no_more_credit,
-    unknown_error
+    delayed_delete,
+    unknown_error,
 };
 
 struct diameter_avp_value {
-	str mac;
+    str mac;
 };
 
 //used to pass data into dialog callbacks
+
 struct impu_data {
     str identity;
     str contact;
 } impu_data_t;
 
-
 struct ro_session {
-    str cdp_session_id;
     volatile int ref;
     int direction;
     struct ro_session* next;
@@ -69,7 +68,7 @@ struct ro_session {
     int auth_session_type;
     int active;
     unsigned int flags;
-    struct diameter_avp_value avp_value;
+    str mac;
     int rating_group;
     int service_identifier;
 };
@@ -141,7 +140,7 @@ extern struct ro_session_table *ro_session_table;
 		if ((_ro_session)->ref<=0) { \
 			unlink_unsafe_ro_session( _ro_session_entry, _ro_session);\
 			LM_DBG("ref <=0 for ro_session %p\n",_ro_session);\
-			destroy_ro_session(_ro_session);\
+                        put_ro_session_on_wait(_ro_session);\
 		}\
 	}while(0)
 
@@ -193,9 +192,9 @@ void link_ro_session(struct ro_session *ro_session, int n);
 
 void remove_aaa_session(str *session_id);
 
-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,
-	int active_rating_group, int active_service_identifier, str *incoming_trunk_id, str *outgoing_trunk_id, str *pani);
+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,
+        int active_rating_group, int active_service_identifier, str *incoming_trunk_id, str *outgoing_trunk_id, str *pani);
 
 /*!
  * \brief Refefence a ro_session with locking
@@ -217,6 +216,8 @@ struct ro_session* lookup_ro_session(unsigned int h_entry, str *callid, int dire
 
 void free_impu_data(struct impu_data *impu_data);
 
+int put_ro_session_on_wait(struct ro_session* session);
+
 
 #endif	/* RO_SESSION_HASH_H */
 

+ 203 - 208
modules/ims_charging/ro_timer.c

@@ -8,6 +8,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
+#include <math.h>
 
 #include "../../mem/shm_mem.h"
 #include "../dialog_ng/dlg_load.h"
@@ -97,10 +98,12 @@ static inline void insert_ro_timer_unsafe(struct ro_tl *tl) {
     }
 
     LM_DBG("inserting %p for %d\n", tl, tl->timeout);
+    LM_DBG("BEFORE ptr [%p], ptr->next [%p], ptr->next->prev [%p]", ptr, ptr->next, ptr->next->prev);
     tl->prev = ptr;
     tl->next = ptr->next;
     tl->prev->next = tl;
     tl->next->prev = tl;
+    LM_DBG("AFTER tl->prev [%p], tl->next [%p]", tl->prev, tl->next);
 }
 
 /*!
@@ -147,7 +150,7 @@ static inline void remove_ro_timer_unsafe(struct ro_tl *tl) {
  */
 int remove_ro_timer(struct ro_tl *tl) {
     lock_get(roi_timer->lock);
-	
+
     if (tl->prev == NULL && tl->timeout == 0) {
         lock_release(roi_timer->lock);
         return 1;
@@ -159,7 +162,7 @@ int remove_ro_timer(struct ro_tl *tl) {
         lock_release(roi_timer->lock);
         return -1;
     }
-    LM_DBG("TIMER REMOVED");
+    LM_DBG("TIMER [%p] REMOVED\n", tl);
     remove_ro_timer_unsafe(tl);
     tl->next = NULL;
     tl->prev = NULL;
@@ -179,6 +182,7 @@ int remove_ro_timer(struct ro_tl *tl) {
 int update_ro_timer(struct ro_tl *tl, int timeout) {
     lock_get(roi_timer->lock);
 
+    LM_DBG("Updating ro timer [%p] with timeout [%d]\n", tl, timeout);
     if (tl->next) {
         if (tl->prev == 0) {
             lock_release(roi_timer->lock);
@@ -204,6 +208,8 @@ static inline struct ro_tl* get_expired_ro_sessions(unsigned int time) {
 
     lock_get(roi_timer->lock);
 
+    LM_DBG("my ticks are [%d]\n", time);
+
     if (roi_timer->first.next == &(roi_timer->first) || roi_timer->first.next->timeout > time) {
         lock_release(roi_timer->lock);
         return 0;
@@ -257,217 +263,206 @@ void ro_timer_routine(unsigned int ticks, void * attr) {
 }
 
 void resume_ro_session_ontimeout(struct interim_ccr *i_req) {
-	time_t now = time(0);
-	time_t used_secs;
-	struct ro_session_entry *ro_session_entry = NULL;
-	int call_terminated = 0;
-
-	if (!i_req) {
-		LM_ERR("This is so wrong: i_req is NULL\n");
-		return;
-	}
-
-	ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);
-	ro_session_lock(ro_session_table, ro_session_entry);
-	LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);
-
-	used_secs = now - i_req->ro_session->last_event_timestamp;
-
-	/* check to make sure diameter server is giving us sane values */
-	if (i_req->new_credit > i_req->credit_valid_for) {
-		LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity period instead \n");
-		i_req->new_credit = i_req->credit_valid_for;
-	}
-
-	if (i_req->new_credit > 0) {
-		//now insert the new timer
-		i_req->ro_session->last_event_timestamp = time(0);
-		i_req->ro_session->event_type = answered;
-		i_req->ro_session->valid_for = i_req->credit_valid_for;
-
-		int ret = 0;
-		if (i_req->is_final_allocation) {
-			LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
-			i_req->ro_session->event_type = no_more_credit;
-			ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
-		}
-		else {
-			int timer_timeout = i_req->new_credit;
-
-			if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {
-
-				// We haven't finished using our 1st block of units, and we need to set the timer to
-				// (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
-				// reservation is exhausted. This will only be done the first time, because the timer
-				// will always be fired 5 seconds before we run out of time thanks to this operation
-
-				if ((now - i_req->ro_session->start_time) /* call time */ < i_req->ro_session->reserved_secs)
-					timer_timeout = i_req->new_credit - ro_timer_buffer;
-				else
-					timer_timeout = i_req->new_credit;
-			}
-
-			ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);
-
-		}
-
-		// update to the new block of units we got
-		i_req->ro_session->reserved_secs = i_req->new_credit;
-
-		if (ret != 0) {
-			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
-					i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
-		}
-		else {
-			ref_ro_session_unsafe(i_req->ro_session, 1);
-		}
-		
-		if (ro_db_mode == DB_MODE_REALTIME) {
-		    i_req->ro_session->flags |= RO_SESSION_FLAG_CHANGED;
-		    if (update_ro_dbinfo_unsafe(i_req->ro_session) != 0) {
-			LM_ERR("Failed to update Ro session in DB... continuing\n");
-		    }
-		}
-	}
-	else {
-		/* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
-		/* also update the event type to no_more_credit to save on processing the next time we get here */
-		i_req->ro_session->event_type = no_more_credit;
-		int whatsleft = i_req->ro_session->reserved_secs - used_secs;
-		if (whatsleft <= 0) {
-			// TODO we need to handle this situation more precisely.
-			// in case CCR times out, we get a call shutdown but the error message assumes it was due to a lack of credit.
-			//
-			LM_WARN("Immediately killing call due to no more credit *OR* no CCA received (timeout) after reservation request\n");
-
-			//
-			// we need to unlock the session or else we might get a deadlock on dlg_terminated() dialog callback.
-			// Do not unref the session because it will be made inside the dlg_terminated() function.
-			//
-
-			//unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);
-			ro_session_unlock(ro_session_table, ro_session_entry);
-
-			dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL );
-			call_terminated = 1;
-		}
-		else {
-			LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
-			int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
-			if (ret != 0) {
-				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
-						i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
-			}
-			else {
-				ref_ro_session_unsafe(i_req->ro_session, 1);
-			}
-		}
-	}
-
-	//
-	// if call was forcefully terminated, the lock was released before dlgb.lookup_terminate_dlg() function call.
-	//
-	if (!call_terminated) {
-		unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);//unref from the initial timer that fired this event.
-		ro_session_unlock(ro_session_table, ro_session_entry);
-	}
-
-	shm_free(i_req);
-	LM_DBG("Exiting async ccr interim nicely");
+    time_t now = get_current_time_micro();
+    long used_secs;
+    struct ro_session_entry *ro_session_entry = NULL;
+    int call_terminated = 0;
+
+    if (!i_req) {
+        LM_ERR("This is so wrong: i_req is NULL\n");
+        return;
+    }
+
+    ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);
+    ro_session_lock(ro_session_table, ro_session_entry);
+    LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);
+
+    used_secs = rint((now - i_req->ro_session->last_event_timestamp) / (float) 1000000);
+
+    /* check to make sure diameter server is giving us sane values */
+    if (i_req->new_credit > i_req->credit_valid_for) {
+        LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity period instead \n");
+        i_req->new_credit = i_req->credit_valid_for;
+    }
+
+    if (i_req->new_credit > 0) {
+        //now insert the new timer
+        i_req->ro_session->last_event_timestamp = get_current_time_micro();
+        i_req->ro_session->event_type = answered;
+        i_req->ro_session->valid_for = i_req->credit_valid_for;
+
+        int ret = 0;
+        if (i_req->is_final_allocation) {
+            LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
+            i_req->ro_session->event_type = no_more_credit;
+            ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
+        } else {
+            int timer_timeout = i_req->new_credit;
+
+            if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {
+
+                // We haven't finished using our 1st block of units, and we need to set the timer to
+                // (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
+                // reservation is exhausted. This will only be done the first time, because the timer
+                // will always be fired 5 seconds before we run out of time thanks to this operation
+                timer_timeout = i_req->new_credit - ro_timer_buffer;
+            }
+
+            ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);
+
+        }
+
+        // update to the new block of units we got
+        i_req->ro_session->reserved_secs = i_req->new_credit;
+
+        if (ret != 0) {
+            LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
+                    i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
+        } else {
+            ref_ro_session_unsafe(i_req->ro_session, 1);
+        }
+
+        if (ro_db_mode == DB_MODE_REALTIME) {
+            i_req->ro_session->flags |= RO_SESSION_FLAG_CHANGED;
+            if (update_ro_dbinfo_unsafe(i_req->ro_session) != 0) {
+                LM_ERR("Failed to update Ro session in DB... continuing\n");
+            }
+        }
+    } else {
+        /* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
+        /* also update the event type to no_more_credit to save on processing the next time we get here */
+        i_req->ro_session->event_type = no_more_credit;
+        int whatsleft = i_req->ro_session->reserved_secs - used_secs;
+        if (whatsleft <= 0) {
+            // TODO we need to handle this situation more precisely.
+            // in case CCR times out, we get a call shutdown but the error message assumes it was due to a lack of credit.
+            //
+            LM_WARN("Immediately killing call due to no more credit *OR* no CCA received (timeout) after reservation request\n");
+
+            //
+            // we need to unlock the session or else we might get a deadlock on dlg_terminated() dialog callback.
+            // Do not unref the session because it will be made inside the dlg_terminated() function.
+            //
+
+            //unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);
+            ro_session_unlock(ro_session_table, ro_session_entry);
+
+            dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL);
+            call_terminated = 1;
+        } else {
+            LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
+            int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
+            if (ret != 0) {
+                LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
+                        i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
+            } else {
+                ref_ro_session_unsafe(i_req->ro_session, 1);
+            }
+        }
+    }
+
+    //
+    // if call was forcefully terminated, the lock was released before dlgb.lookup_terminate_dlg() function call.
+    //
+    if (!call_terminated) {
+        unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry); //unref from the initial timer that fired this event.
+        ro_session_unlock(ro_session_table, ro_session_entry);
+    }
+
+    shm_free(i_req);
+    LM_DBG("Exiting async ccr interim nicely");
 }
 
 /* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit.
  * If we cant we need to put a new timer to kill the call at the appropriate time
  */
 void ro_session_ontimeout(struct ro_tl *tl) {
-	time_t now, used_secs, call_time;
-
-	LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout);
-
-	/* find the session id for this timer*/
-	struct ro_session* ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl)));
-
-	if (!ro_session) {
-		LM_ERR("Can't find a session. This is bad");
-		return;
-	}
-
-	LM_DBG("event-type=%d", ro_session->event_type);
-	
-//	if (!ro_session->active) {
-//		LM_ALERT("Looks like this session was terminated while requesting more units");
-//		goto exit;
-//		return;
-//	}
-	
-	switch (ro_session->event_type) {
-	case answered:
-		now = time(0);
-		used_secs = now - ro_session->last_event_timestamp;
-		call_time = now - ro_session->start_time;
-
-		counter_add(ims_charging_cnts_h.billed_secs, used_secs);
-
-		if (ro_session->callid.s != NULL
-				&& ro_session->dlg_h_entry	>= 0
-				&& ro_session->dlg_h_id > 0
-				&& ro_session->ro_session_id.s != NULL)
-		{
-			LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n",
-					ro_session->ro_session_id.len,
-					ro_session->ro_session_id.s,
-					ro_session->asserted_identity.len,
-					ro_session->asserted_identity.s);
-
-			LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago",
-					(unsigned int) call_time,
-					(unsigned int) ro_session->reserved_secs,
-					(unsigned int) used_secs);
-
-			LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n",
-					ro_session,
-					interim_request_credits/* new reservation request amount */,
-					(unsigned int) used_secs/* charged seconds from previous reservation */);
-
-			// Apply for more credit.
-			//
-			// The function call will return immediately and we will receive the reply asynchronously via a callback
-			send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits);
-			return;
-		}
-		else {
-			LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n");
-			/* put the timer back so the call will be killed according to previous timeout. */
-			ro_session->event_type = unknown_error;
-			int ret = insert_ro_timer(&ro_session->ro_tl,
-					ro_session->reserved_secs - used_secs);
-			if (ret != 0) {
-				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", 
-					ro_session->ro_session_id.len, ro_session->ro_session_id.s); 
-			}
-			else {
-				ref_ro_session_unsafe(ro_session, 1);
-			}
-			LM_ERR("Immediately killing call due to unknown error\n");
-		}
-
-		break;
-	default:
-		LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type);
-
-		if (ro_session->event_type == no_more_credit)
-			LM_INFO("Call/session must be ended - no more funds.\n");
-		else if (ro_session->event_type == unknown_error)
-			LM_ERR("last event caused an error. We will now tear down this session.\n");
-	}
-
-
-	counter_inc(ims_charging_cnts_h.killed_calls);
-
-	//unref_ro_session_unsafe(ro_session, 1, ro_session_entry); //unref from the initial timer that fired this event.
-//	ro_session_unlock(ro_session_table, ro_session_entry);
-
-	dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, NULL);
-	return;
+    time_t now, call_time;
+    long used_secs;
+
+    LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout);
+
+    /* find the session id for this timer*/
+    struct ro_session* ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl)));
+    LM_DBG("offset for ro_tl is [%lu] and ro_session id is [%.*s]\n", (unsigned long) (&((struct ro_session*) 0)->ro_tl), ro_session->ro_session_id.len, ro_session->ro_session_id.s);
+
+    if (!ro_session) {
+        LM_ERR("Can't find a session. This is bad");
+        return;
+    }
+
+    LM_DBG("event-type=%d", ro_session->event_type);
+
+    //	if (!ro_session->active) {
+    //		LM_ALERT("Looks like this session was terminated while requesting more units");
+    //		goto exit;
+    //		return;
+    //	}
+
+    switch (ro_session->event_type) {
+        case answered:
+            now = get_current_time_micro();
+            used_secs = rint((now - ro_session->last_event_timestamp) / (float) 1000000);
+            call_time = rint((now - ro_session->start_time) / (float) 1000000);
+
+            counter_add(ims_charging_cnts_h.billed_secs, used_secs);
+
+            if (ro_session->callid.s != NULL
+                    && ro_session->dlg_h_entry >= 0
+                    && ro_session->dlg_h_id > 0
+                    && ro_session->ro_session_id.s != NULL) {
+                LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n",
+                        ro_session->ro_session_id.len,
+                        ro_session->ro_session_id.s,
+                        ro_session->asserted_identity.len,
+                        ro_session->asserted_identity.s);
+
+                LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago",
+                        (unsigned int) call_time,
+                        (unsigned int) ro_session->reserved_secs,
+                        (unsigned int) used_secs);
+
+                LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n",
+                        ro_session,
+                        interim_request_credits/* new reservation request amount */,
+                        (unsigned int) used_secs/* charged seconds from previous reservation */);
+
+                // Apply for more credit.
+                //
+                // The function call will return immediately and we will receive the reply asynchronously via a callback
+                send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits);
+                return;
+            } else {
+                LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n");
+                /* put the timer back so the call will be killed according to previous timeout. */
+                ro_session->event_type = unknown_error;
+                int ret = insert_ro_timer(&ro_session->ro_tl,
+                        (ro_session->reserved_secs - used_secs) / 1000000);
+                if (ret != 0) {
+                    LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
+                            ro_session->ro_session_id.len, ro_session->ro_session_id.s);
+                } else {
+                    ref_ro_session_unsafe(ro_session, 1);
+                    return;
+                }
+                LM_ERR("Immediately killing call due to unknown error\n");
+            }
+            break;
+        case delayed_delete:
+            destroy_ro_session(ro_session);
+            return;
+        default:
+            LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type);
+
+            if (ro_session->event_type == no_more_credit)
+                LM_INFO("Call/session must be ended - no more funds.\n");
+            else if (ro_session->event_type == unknown_error)
+                LM_ERR("last event caused an error. We will now tear down this session.\n");
+    }
+
+    counter_inc(ims_charging_cnts_h.killed_calls);
+
+    dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, NULL);
+    return;
 }
 

+ 15 - 3
modules/ims_qos/cdpeventprocessor.c

@@ -173,6 +173,7 @@ void cdp_cb_event_process() {
     cdp_cb_event_t *ev;
     udomain_t* domain;
     pcontact_t* pcontact;
+    pcontact_info_t contact_info;
 
     struct pcontact_info ci;
     memset(&ci, 0, sizeof (struct pcontact_info));
@@ -248,8 +249,19 @@ void cdp_cb_event_process() {
 			    LM_DBG("Unable to register usrloc domain....aborting\n");
 			    return;
 			}
-			ul.lock_udomain(domain, &p_session_data->registration_aor, &p_session_data->ip, p_session_data->recv_port);
-			if (ul.get_pcontact(domain, &p_session_data->registration_aor, &p_session_data->ip, p_session_data->recv_port, &pcontact) != 0) {
+			ul.lock_udomain(domain, &p_session_data->via_host, p_session_data->via_port, p_session_data->via_proto);
+                        
+                        contact_info.received_host = p_session_data->ip;
+                        contact_info.received_port = p_session_data->recv_port;
+                        contact_info.received_proto = p_session_data->recv_proto;
+                        contact_info.searchflag = (1 << SEARCH_RECEIVED);
+                        
+                        contact_info.via_host = p_session_data->via_host;
+                        contact_info.via_port = p_session_data->via_port;
+                        contact_info.via_prot = p_session_data->via_proto;
+                        contact_info.aor = p_session_data->registration_aor;
+                        
+			if (ul.get_pcontact(domain, &contact_info, &pcontact) != 0) {
 			    LM_DBG("no contact found for terminated Rx reg session..... ignoring\n");
 			} else {
 			    LM_DBG("Updating contact [%.*s] after Rx reg session terminated, setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);
@@ -257,7 +269,7 @@ void cdp_cb_event_process() {
 			    ci.num_service_routes = 0;
 			    ul.update_pcontact(domain, &ci, pcontact);
 			}
-			ul.unlock_udomain(domain, &p_session_data->registration_aor, &p_session_data->ip, p_session_data->recv_port);
+			ul.unlock_udomain(domain, &p_session_data->via_host, p_session_data->via_port, p_session_data->via_proto);
 			counter_add(ims_qos_cnts_h.active_registration_rx_sessions, -1);
 		    }
                 } else {

+ 64 - 25
modules/ims_qos/mod.c

@@ -589,7 +589,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* dir, char *c_id, int
     str s_id;
     struct hdr_field *h=0;
     struct dlg_cell* dlg = 0;
-
+    
     cfg_action_t* cfg_action = 0;
     saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
     char* direction = dir;
@@ -622,7 +622,6 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* dir, char *c_id, int
     //We don't ever do AAR on request for calling scenario...
     if (msg->first_line.type != SIP_REPLY) {
         LM_DBG("Can't do AAR for call session in request\n");
-		result = CSCF_RETURN_FALSE;
         return result;
     }
 
@@ -635,19 +634,17 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* dir, char *c_id, int
     }
 
     //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK!
-    if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0) 
-		|| (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0 
-		|| memcmp(t->method.s, "UPDATE", 6) == 0))) {
-			if (cscf_get_content_length(msg) == 0 
-				|| cscf_get_content_length(t->uas.request) == 0) {
-				LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR");
-				//goto aarna; //AAR na if we dont have offer/answer pair
-				result = CSCF_RETURN_FALSE;
-				return result;
-			}
+    if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0)
+            || (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0
+            || memcmp(t->method.s, "UPDATE", 6) == 0))) {
+        if (cscf_get_content_length(msg) == 0
+                || cscf_get_content_length(t->uas.request) == 0) {
+            LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR");
+            //goto aarna; //AAR na if we dont have offer/answer pair
+            return result;
+        }
     } else {
         LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR");
-		result = CSCF_RETURN_FALSE;
         return result;
     }
 
@@ -882,7 +879,13 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* dir, char *c_id, int
         LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction);
     } else {
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
-	saved_t_data->aar_update = 1;//this is an update aar - we set this so on async_aar we know this is an update and act accordingly
+        //check if this is triggered by a 183 - if so break here as its probably a re-transmit
+        if((msg->first_line).u.reply.statuscode == 183) {
+            LM_ERR("Received a 183 for a diameter session that already exists - just going to ignore this\n");
+            cdpb.AAASessionsUnlock(auth_session->hash);
+            goto ignore;
+        }
+        saved_t_data->aar_update = 1;//this is an update aar - we set this so on async_aar we know this is an update and act accordingly
     }
 
     LM_DBG("Suspending SIP TM transaction\n");
@@ -909,6 +912,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* dir, char *c_id, int
 
 error:
     LM_ERR("Error trying to send AAR (calling)\n");
+ignore:
     if (saved_t_data)
         free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
     //otherwise the callback will segfault
@@ -924,6 +928,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
     contact_t* c;
     struct hdr_field* h;
     pcontact_t* pcontact;
+    pcontact_info_t contact_info;
     contact_body_t* cb = 0;
     AAASession* auth;
     rx_authsessiondata_t* rx_regsession_data_p;
@@ -935,6 +940,11 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
     saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
     str recv_ip;
     int recv_port;
+    unsigned short recv_proto;
+    
+    struct via_body* vb;
+    unsigned short via_port;
+    unsigned short via_proto;
     
     if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
         LM_ERR("no async route block for assign_server_unreg\n");
@@ -1001,6 +1011,10 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
         }
     }
 
+    vb = cscf_get_ue_via(msg);
+    via_port = vb->port?vb->port:5060;
+    via_proto = vb->proto;
+    
     //before we continue, make sure we have a transaction to work with (viz. cdp async)
     t = tmb.t_gett();
     if (t == NULL || t == T_UNDEFINED) {
@@ -1053,17 +1067,27 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
     recv_ip.s = ip_addr2a(&msg->rcv.src_ip);
     recv_ip.len = strlen(ip_addr2a(&msg->rcv.src_ip));
     recv_port = msg->rcv.src_port;
+    recv_proto = msg->rcv.proto; 
+    
     LM_DBG("Message received IP address is: [%.*s]\n", recv_ip.len, recv_ip.s);
-    uint16_t ip_version = AF_INET; //TODO IPv6!!!?
+    LM_DBG("Message via is [%d://%.*s:%d]\n", vb->proto, vb->host.len, vb->host.s, via_port);
 
     lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously
     for (h = msg->contact; h; h = h->next) {
         if (h->type == HDR_CONTACT_T && h->parsed) {
             for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
-                ul.lock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
-                if (ul.get_pcontact(domain_t, &c->uri, &recv_ip, recv_port, &pcontact) != 0) {
-                    LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n");
-                    ul.unlock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
+                ul.lock_udomain(domain_t, &vb->host, vb->port, vb->proto);
+                contact_info.aor = c->uri;
+                contact_info.via_host = vb->host;
+                contact_info.via_port = vb->port;
+                contact_info.via_prot = vb->proto;
+                contact_info.searchflag = SEARCH_NORMAL;
+                contact_info.received_host.s = 0;
+                contact_info.received_host.len = 0;
+                
+                if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) {
+                    LM_ERR("This contact does not exist in PCSCF usrloc - error in cfg file\n");
+                    ul.unlock_udomain(domain_t, &vb->host, vb->port, vb->proto);
                     lock_release(saved_t_data->lock);
                     goto error;
                 } else if (pcontact->reg_state == PCONTACT_REG_PENDING
@@ -1087,10 +1111,10 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                         is_rereg = 1;
                     } else {
                         LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s);
-                        int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &recv_ip, ip_version, recv_port, &rx_regsession_data_p);
+                        int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &recv_ip, AF_INET /* TODO: IPv6 support */, recv_port, recv_proto, &vb->host, vb->port, vb->proto, &rx_regsession_data_p);
                         if (!ret) {
                             LM_ERR("Unable to create regsession data parcel for rx_session_id [%.*s]...Aborting\n", pcontact->rx_session_id.len, pcontact->rx_session_id.s);
-                            ul.unlock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
+                            ul.unlock_udomain(domain_t, &vb->host, vb->port, vb->proto);
                             if (rx_regsession_data_p) {
                                 shm_free(rx_regsession_data_p);
                                 rx_regsession_data_p = 0;
@@ -1105,7 +1129,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                                 shm_free(rx_regsession_data_p);
                                 rx_regsession_data_p = 0;
                             }
-                            ul.unlock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
+                            ul.unlock_udomain(domain_t, &vb->host, via_port, via_proto);
                             if (auth) cdpb.AAASessionsUnlock(auth->hash);
                             if (rx_regsession_data_p) {
                                 shm_free(rx_regsession_data_p);
@@ -1118,7 +1142,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                     }
 
                     //we are ready to send the AAR async. lets save the local data data
-                    int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len;
+                    int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len + vb->host.len + recv_ip.len;
                     local_data = shm_malloc(local_data_len);
                     if (!local_data) {
                         LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
@@ -1141,6 +1165,21 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                     memcpy(p, auth->id.s, auth->id.len);
                     p += auth->id.len;
 
+                    local_data->via_host.s = p;
+                    local_data->via_host.len = vb->host.len;
+                    memcpy(p, vb->host.s, vb->host.len);
+                    p += vb->host.len;
+                    
+                    local_data->recv_host.s = p;
+                    local_data->recv_host.len = recv_ip.len;
+                    memcpy(p, recv_ip.s, recv_ip.len);
+                    p += recv_ip.len;
+                    
+                    local_data->via_port = via_port;
+                    local_data->via_proto = via_proto;
+                    local_data->recv_port = recv_port;
+                    local_data->recv_proto = recv_proto;
+                    
                     if (p != (((char*) local_data) + local_data_len)) {
                         LM_CRIT("buffer overflow\n");
                         free_saved_transaction_data(local_data);
@@ -1153,7 +1192,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                     //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
                     ret = rx_send_aar_register(msg, auth, local_data); //returns a locked rx auth object
 
-                    ul.unlock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
+                    ul.unlock_udomain(domain_t, &vb->host, via_port, via_proto);
 
                     if (!ret) {
                         LM_ERR("Failed to send AAR\n");
@@ -1168,7 +1207,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char*
                 } else {
                     //contact exists - this is a re-registration, for now we just ignore this
                     LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n");
-                    ul.unlock_udomain(domain_t, &c->uri, &recv_ip, recv_port);
+                    ul.unlock_udomain(domain_t, &vb->host, via_port, via_proto);
                     //now we loop for any other contacts.
                 }
             }

+ 26 - 36
modules/ims_qos/rx_aar.c

@@ -98,8 +98,6 @@ void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
     struct cell *t = 0;
     unsigned int cdp_result;
     int result = CSCF_RETURN_ERROR;
-    AAASession *auth = 0;
-    rx_authsessiondata_t* p_session_data = 0;
     
     LM_DBG("Received AAR callback\n");
     saved_transaction_t* data = (saved_transaction_t*) param;
@@ -147,29 +145,8 @@ void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
 	LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);
 
 	if(!data->aar_update) {
-	    LM_DBG("This is an AAA response to an initial AAR - active_media_rx_sessions");
-	    
-	    //need to set Rx auth data to say this session has been successfully opened
-	    //This is used elsewhere to prevent acting on termination events when the session has not been opened
-	    //getting auth session
-	    auth = cdpb.AAAGetAuthSession(aaa->sessionId->data);
-	    if (!auth) {
-		LM_DBG("Could not get Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
-		goto error;
-	    }
-	    //getting session data
-	    p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
-	    if (!p_session_data) {
-		LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s);
-		if (auth) cdpb.AAASessionsUnlock(auth->hash);
-		goto error;
-	    }
-	    
-	    LM_DBG("Setting session_has_been_opened and incrementing active_media_rx_sessions\n");
-	    p_session_data->session_has_been_opened = 1;
+	    LM_DBG("This is an AAA response to an initial AAR");
 	    counter_inc(ims_qos_cnts_h.active_media_rx_sessions);
-
-	    if (auth) cdpb.AAASessionsUnlock(auth->hash);
 	    
 	    str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
 	    passed_rx_session_id->s = 0;
@@ -216,6 +193,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
     AAASession *auth = 0;
     rx_authsessiondata_t* p_session_data = 0;
     int result = CSCF_RETURN_ERROR;
+    pcontact_info_t contact_info;
 
     LM_DBG("Received AAR callback\n");
     saved_transaction_local_t* local_data = (saved_transaction_local_t*) param;
@@ -275,7 +253,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
 
     if (cdp_result >= 2000 && cdp_result < 3000) {
         counter_inc(ims_qos_cnts_h.successful_registration_aars);
-        if (is_rereg) {
+	if (is_rereg) {
             LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
             result = CSCF_RETURN_TRUE;
             create_return_code(result);
@@ -296,7 +274,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
 	    if (auth) cdpb.AAASessionsUnlock(auth->hash);
 	    goto error;
 	}
-	    p_session_data->session_has_been_opened = 1;
+	p_session_data->session_has_been_opened = 1;
 	counter_inc(ims_qos_cnts_h.active_registration_rx_sessions);
 	
 	if (auth) cdpb.AAASessionsUnlock(auth->hash);
@@ -307,10 +285,22 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
                 local_data->auth_session_id.len, local_data->auth_session_id.s);
         LM_DBG("Registering for Usrloc callbacks on DELETE\n");
 
-        ul.lock_udomain(domain_t, &local_data->contact, &p_session_data->ip, p_session_data->recv_port);
-        if (ul.get_pcontact(domain_t, &local_data->contact, &p_session_data->ip, p_session_data->recv_port, &pcontact) != 0) {
-            LM_ERR("Shouldn't get here, can find contact....\n");
-            ul.unlock_udomain(domain_t, &local_data->contact, &p_session_data->ip, p_session_data->recv_port);
+        ul.lock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
+        
+        contact_info.received_host = local_data->recv_host;
+        contact_info.received_port = local_data->recv_port;
+        contact_info.received_proto = local_data->recv_proto;
+        contact_info.searchflag = (1 << SEARCH_RECEIVED);
+        
+        
+        contact_info.aor = local_data->contact;
+        contact_info.via_host = local_data->via_host;
+        contact_info.via_port = local_data->via_port;
+        contact_info.via_prot = local_data->via_proto;
+        
+        if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) {
+            LM_ERR("Shouldn't get here, can't find contact....\n");
+            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
             goto error;
         }
 
@@ -320,7 +310,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
          * */
         if (ul.update_rx_regsession(domain_t, &local_data->auth_session_id, pcontact) != 0) {
             LM_ERR("unable to update pcontact......\n");
-            ul.unlock_udomain(domain_t, &local_data->contact, &p_session_data->ip, p_session_data->recv_port);
+            ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
             goto error;
         }
         memset(&ci, 0, sizeof (struct pcontact_info));
@@ -332,7 +322,7 @@ void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long e
         //register for callbacks on contact
         ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE,
                 callback_pcscf_contact_cb, NULL);
-        ul.unlock_udomain(domain_t, &local_data->contact, &p_session_data->ip, p_session_data->recv_port);
+        ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto);
         result = CSCF_RETURN_TRUE;
     } else {
         LM_DBG("Received negative reply from PCRF for AAR Request\n");
@@ -526,7 +516,7 @@ int rx_send_aar_update_no_video(AAASession* auth) {
     char x[4];
     int ret = 0;
 
-    str ip;
+    str recv_ip;
     uint16_t ip_version;
 
     //we get ip and identifier for the auth session data 
@@ -534,7 +524,7 @@ int rx_send_aar_update_no_video(AAASession* auth) {
     p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
     identifier = p_session_data->identifier;
     identifier_type = p_session_data->identifier_type;
-    ip = p_session_data->ip;
+    recv_ip = p_session_data->ip;
     ip_version = p_session_data->ip_version;
     
     aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);
@@ -630,9 +620,9 @@ int rx_send_aar_update_no_video(AAASession* auth) {
 
     add_media_components_using_current_flow_description(aar, p_session_data);
 
-    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
+    LM_DBG("Adding framed ip address [%.*s]\n", recv_ip.len, recv_ip.s);
     /* Add Framed IP address AVP*/
-    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
+    if (!rx_add_framed_ip_avp(&aar->avpList, recv_ip, ip_version)) {
         LM_ERR("Unable to add framed IP AVP\n");
         goto error;
     }

+ 7 - 1
modules/ims_qos/rx_aar.h

@@ -76,7 +76,13 @@ typedef struct saved_transaction {
 
 typedef struct saved_transaction_local {
 	int is_rereg;
-	str contact;
+        str contact;                /* contact AOR */
+	str via_host;                   /* host address of UE - first via for REQUEST, last via for REPLY */
+        unsigned short via_port;        /* port of UE based on VIA */
+        unsigned short via_proto;       /* via proto */
+        str recv_host;                   /* host address of UE - first via for REQUEST, last via for REPLY */
+        unsigned short recv_port;        /* port of UE based on VIA */
+        unsigned short recv_proto;       /* via proto */
 	str auth_session_id;
 	saved_transaction_t* global_data;
 } saved_transaction_local_t;

+ 15 - 6
modules/ims_qos/rx_authdata.c

@@ -68,9 +68,9 @@
 #include "../../lib/ims/ims_getters.h"
 #include "mod.h"
 
-int create_new_regsessiondata(str* domain, str* aor, str *ip, int ip_version, int recv_port, rx_authsessiondata_t** session_data) {
+int create_new_regsessiondata(str* domain, str* aor,  str *ip, int ip_version, int recv_port, unsigned short recv_proto, str *via_host, unsigned short via_port, unsigned short via_proto, rx_authsessiondata_t** session_data) {
 
-	int len = (domain->len + 1) + aor->len + ip->len + sizeof(rx_authsessiondata_t);
+	int len = (domain->len + 1) + ip->len + aor->len + via_host->len + sizeof(rx_authsessiondata_t);
 	rx_authsessiondata_t* p_session_data = shm_malloc(len);
 	if (!p_session_data) {
 		LM_ERR("no more shm memory\n");
@@ -82,8 +82,12 @@ int create_new_regsessiondata(str* domain, str* aor, str *ip, int ip_version, in
         p_session_data->must_terminate_dialog = 0; /*irrelevent for reg session data this will always be 0 */
 
 	p_session_data->session_has_been_opened = 0; /*0 has not been opened 1 has been opened*/
-	p_session_data->ip_version = ip_version;
-	p_session_data->recv_port = recv_port;
+	p_session_data->ip_version = ip_version;   
+	p_session_data->via_port = via_port;
+        p_session_data->via_proto = via_proto;
+        
+        p_session_data->recv_port = recv_port;
+        p_session_data->recv_proto = recv_proto;
 	
 	char* p = (char*)(p_session_data + 1);
 	p_session_data->domain.s = p;
@@ -97,10 +101,15 @@ int create_new_regsessiondata(str* domain, str* aor, str *ip, int ip_version, in
 	p_session_data->registration_aor.len = aor->len;
 	p += aor->len;
 	
-	p_session_data->ip.s = p;
+        p_session_data->ip.s = p;
 	memcpy(p, ip->s, ip->len);
 	p_session_data->ip.len = ip->len;
 	p += ip->len;
+        
+	p_session_data->via_host.s = p;
+	memcpy(p, via_host->s, via_host->len);
+	p_session_data->via_host.len = via_host->len;
+	p += via_host->len;
 	
 	if (p != (((char*)p_session_data) + len)) {
 		LM_ERR("buffer over/underflow\n");
@@ -338,7 +347,7 @@ void free_callsessiondata(rx_authsessiondata_t* session_data) {
     if(!session_data){
 	return;
     }
-    
+    LM_DBG("Freeing session data for [%.*s]\n", session_data->via_host.len, session_data->via_host.s);
     LM_DBG("Destroy current flow description\n");
     free_flow_description(session_data, 1);
     

+ 6 - 2
modules/ims_qos/rx_authdata.h

@@ -81,9 +81,13 @@ typedef struct rx_authsessiondata {
     str ttag;
     str identifier;
     int identifier_type;
+    str via_host;       /* UE host as fetched from Via (first for REQUEST, last for REPLY) */
+    unsigned short via_port; /* UE port as fetched from Via (first for REQUEST, last for REPLY) */
+    unsigned short via_proto; /* UE proto as fetched from Via (first for REQUEST, last for REPLY) */
     str ip;
-    int recv_port;
     int ip_version;
+    int recv_port;
+    unsigned short recv_proto;
     //for registration session
     int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
     int session_has_been_opened; // 0 has not been opened 1 has been opened
@@ -94,7 +98,7 @@ typedef struct rx_authsessiondata {
     flow_description_t *first_new_flow_description;
 } rx_authsessiondata_t;
 
-int create_new_regsessiondata(str* domain, str* aor,  str *ip, int ip_version, int recv_port, rx_authsessiondata_t** session_data);
+int create_new_regsessiondata(str* domain, str* aor,  str *ip, int ip_version, int recv_port, unsigned short recv_proto, str *via_host, unsigned short via_port, unsigned short via_proto, rx_authsessiondata_t** session_data);
 int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, int identifier_type, str *ip, int ip_version, rx_authsessiondata_t** session_data);
 void free_callsessiondata(rx_authsessiondata_t* session_data);
 

+ 0 - 107
modules/ims_registrar_pcscf/lookup.c

@@ -1,107 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2012 Smile Communications, [email protected]
- * Copyright (C) 2012 Smile Communications, [email protected]
- * 
- * The initial version of this code was written by Dragos Vingarzan
- * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
- * Fruanhofer Institute. It was and still is maintained in a separate
- * branch of the original SER. We are therefore migrating it to
- * Kamailio/SR and look forward to maintaining it from here on out.
- * 2011/2012 Smile Communications, Pty. Ltd.
- * ported/maintained/improved by 
- * Jason Penton (jason(dot)penton(at)smilecoms.com and
- * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
- * effort to add full IMS support to Kamailio/SR using a new and
- * improved architecture
- * 
- * NB: Alot of this code was originally part of OpenIMSCore,
- * FhG Fokus. 
- * Copyright (C) 2004-2006 FhG Fokus
- * Thanks for great work! This is an effort to 
- * break apart the various CSCF functions into logically separate
- * components. We hope this will drive wider use. We also feel
- * that in this way the architecture is more complete and thereby easier
- * to manage in the Kamailio/SR environment
- *
- * 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
- * 
- */
-
-#include <string.h>
-#include "reg_mod.h"
-#include "lookup.h"
-
-extern usrloc_api_t ul;
-
-/*! \brief
- * Lookup contact in the database and rewrite Request-URI
- * \return:  1 : contacts found and returned
- *          -1 : not found
- *          -2 : error
- */
-int lookup_transport(struct sip_msg* _m, udomain_t* _d, str* _uri) {
-    str uri;
-    pcontact_t* pcontact;
-    char tmp[MAX_URI_SIZE];
-    str received_host = {0,0};
-    str tmp_s;
-    int ret = 1;
-
-    if (_m->new_uri.s) uri = _m->new_uri;
-    else uri = _m->first_line.u.request.uri;
-
-    //now lookup in usrloc
-    ul.lock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
-    if (ul.get_pcontact(_d, &uri, &received_host, _m->rcv.src_port, &pcontact) != 0) { //need to insert new contact
-	LM_WARN("received request for contact that we don't know about\n");
-	ret = -1;
-	goto done;
-    }
-    
-    if (pcontact->received_proto != _m->rcv.proto) {
-	reset_dst_uri(_m);
-	memset(tmp, 0, MAX_URI_SIZE);	
-	switch (pcontact->received_proto) {
-	    case PROTO_TCP:
-		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=tcp", pcontact->aor.len, pcontact->aor.s);
-		break;
-	    case PROTO_UDP:
-		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=udp", pcontact->aor.len, pcontact->aor.s);
-		break;
-	    default:
-		LM_WARN("unsupported transport [%d]\n", pcontact->received_proto);
-		ret = -2;
-		goto done;
-	}
-
-	tmp_s.s = tmp;
-	tmp_s.len = strlen(tmp);
-	if (set_dst_uri(_m, &tmp_s) < 0) {
-	    LM_ERR("failed to set dst_uri for terminating UE\n");
-	    ret = -2;
-	    goto done;
-	}	
-	LM_DBG("Changed dst URI transport for UE to [%.*s]\n", tmp_s.len, tmp_s.s);
-    }
-	
-done:
-    ul.unlock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
-    return ret;
-}
-

+ 0 - 59
modules/ims_registrar_pcscf/lookup.h

@@ -1,59 +0,0 @@
-/*
- * $Id$
- *
- * Copyright (C) 2012 Smile Communications, [email protected]
- * Copyright (C) 2012 Smile Communications, [email protected]
- * 
- * The initial version of this code was written by Dragos Vingarzan
- * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
- * Fruanhofer Institute. It was and still is maintained in a separate
- * branch of the original SER. We are therefore migrating it to
- * Kamailio/SR and look forward to maintaining it from here on out.
- * 2011/2012 Smile Communications, Pty. Ltd.
- * ported/maintained/improved by 
- * Jason Penton (jason(dot)penton(at)smilecoms.com and
- * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
- * effort to add full IMS support to Kamailio/SR using a new and
- * improved architecture
- * 
- * NB: Alot of this code was originally part of OpenIMSCore,
- * FhG Fokus. 
- * Copyright (C) 2004-2006 FhG Fokus
- * Thanks for great work! This is an effort to 
- * break apart the various CSCF functions into logically separate
- * components. We hope this will drive wider use. We also feel
- * that in this way the architecture is more complete and thereby easier
- * to manage in the Kamailio/SR environment
- *
- * 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
- * 
- */
-
-#ifndef LOOKUP_H
-#define	LOOKUP_H
-
-#include "../../parser/msg_parser.h"
-#include "../../modules/ims_usrloc_pcscf/usrloc.h"
-
-
-/*! \brief
- * Lookup a contact in ims_usrloc_pcscf and rewrite R-URI if found and received request transport is different to contact transport
- */
-int lookup_transport(struct sip_msg* _m, udomain_t* _d, str* _uri);
-
-#endif	/* LOOKUP_H */
-

+ 401 - 323
modules/ims_registrar_pcscf/notify.c

@@ -72,356 +72,434 @@
 
 #define RESULT_ERROR -1
 #define RESULT_CONTACTS_FOUND 1
+#define RESULT_TERMINATED_SUCCESS 1
+
+
 
 extern usrloc_api_t ul;
 extern time_t time_now;
 
-int process_contact(udomain_t * _d, int expires, str contact_uri, str * received_host, int received_port, int contact_state) {
-	
-	pcontact_t* pcontact;
-	
-	struct pcontact_info ci;
-	
-	int local_time_now;
-	int ret = RESULT_CONTACTS_FOUND;
-
-	pcscf_act_time();
-	local_time_now = time_now;
-	
-	//get contact
-	//if does not exist then add it
-	//if it does exist check if state it terminated - if so delete it, if not update it
-	
-	memset(&ci, 0, sizeof(struct pcontact_info));
-	ci.num_public_ids=0;
-	ci.num_service_routes=0;
-	
-	expires = local_time_now + expires;  //turn expires into correct time since epoch format
-	LM_DBG("Changed expires to format time since the epoch: %d", expires);
-	ci.expires=expires;
-	ci.reg_state = PCONTACT_REGISTERED;
-	
-	
-	ul.lock_udomain(_d, &contact_uri, received_host, received_port);
-	
-	if (ul.get_pcontact(_d, &contact_uri, received_host, received_port, &pcontact) != 0) { //contact does not exist
-	    if (contact_state == STATE_TERMINATED) {
-		LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s);
-		ret = RESULT_CONTACTS_FOUND;
-		goto done;
-	    }
-		LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now);
-		if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) {
-			LM_ERR("Failed inserting new pcontact\n");
-			ret = RESULT_ERROR;
-			goto done;
-		} else {
-			//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
-			LM_DBG("registering for UL callback\n");
-			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
-		}
-	} else {//contact exists
-		if (contact_state == STATE_TERMINATED) {
-			//delete contact
-			LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
-			if (ul.delete_pcontact(_d, &contact_uri, received_host, received_port, pcontact) != 0) {
-				LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s);
-			}
-		}else {//state is active
-			//update this contact
-			LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s,
-									pcontact->expires,
-									expires,
-									expires-local_time_now);
-			if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
-				LM_ERR("failed to update pcscf contact\n");
-				ret = RESULT_ERROR;
-				goto done;
-			}
-			pcontact->expires = expires;
-		}
-	}
-	
-done:	 
-	ul.unlock_udomain(_d, &contact_uri, received_host, received_port);
-	return ret;
-}
+int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) {
+    char bufport[5], *rest, *sep, *val, *port, *trans;
+    pcontact_t* pcontact;
+    struct pcontact_info ci;
+    struct sip_uri puri, uri;
+    unsigned int received_proto, received_port_len;
+    int local_time_now, rest_len, val_len, has_alias;
+    int ret = RESULT_CONTACTS_FOUND;
+
+    pcscf_act_time();
+    local_time_now = time_now;
+
+    has_alias = 0;
+
+    //get contact
+    //if does not exist then add it
+    //if it does exist check if state it terminated - if so delete it, if not update it
+
+    memset(&ci, 0, sizeof (struct pcontact_info));
+    ci.num_public_ids = 0;
+    ci.num_service_routes = 0;
+
+    LM_DBG("Processing contact using contact from NOTIFY [%.*s]\n", contact_uri.len, contact_uri.s);
+    if (parse_uri(contact_uri.s, contact_uri.len, &puri) < 0) {
+        LM_DBG("Error parsing Contact URI <%.*s>\n", contact_uri.len, contact_uri.s);
+        return RESULT_ERROR;
+    }
+
+    expires = local_time_now + expires; //turn expires into correct time since epoch format
+    LM_DBG("Changed expires to format time since the epoch: %d", expires);
+    ci.expires = expires;
+    ci.reg_state = PCONTACT_REGISTERED;
+
+
+    ul.lock_udomain(_d, &puri.host, puri.port_no, puri.proto);
+    ci.aor = contact_uri;
+    ci.via_host = puri.host;
+    ci.via_prot = puri.proto;
+    ci.via_port = puri.port_no;
 
+    /* parse the uri in the NOTIFY */
+    if (parse_uri(contact_uri.s, contact_uri.len, &uri) != 0) {
+        LM_ERR("Unable to parse contact in SIP notify [%.*s]\n", contact_uri.len, contact_uri.s);
+        return RESULT_ERROR;
+    }
+    /*check for alias - NAT */
+    rest = uri.sip_params.s;
+    rest_len = uri.sip_params.len;
+
+    while (rest_len >= ALIAS_LEN) {
+        if (strncmp(rest, ALIAS, ALIAS_LEN) == 0) {
+            has_alias = 1;
+            break;
+        }
+        sep = memchr(rest, 59 /* ; */, rest_len);
+        if (sep == NULL) {
+            LM_DBG("no alias param\n");
+            break;
+        } else {
+            rest_len = rest_len - (sep - rest + 1);
+            rest = sep + 1;
+        }
+    }
+
+    if (has_alias) {
+        val = rest + ALIAS_LEN;
+        val_len = rest_len - ALIAS_LEN;
+        port = memchr(val, 126 /* ~ */, val_len);
+        if (port == NULL) {
+            LM_ERR("no '~' in alias param value\n");
+            return RESULT_ERROR;
+        }
+        port++;
+        //            received_port = atoi(port);
+        trans = memchr(port, 126 /* ~ */, val_len - (port - val));
+        if (trans == NULL) {
+            LM_ERR("no second '~' in alias param value\n");
+            return RESULT_ERROR;
+        }
+
+        received_port_len = trans - port;
+
+        trans = trans + 1;
+        received_proto = *trans - 48 /* char 0 */;
+
+        memcpy(bufport, port, received_port_len);
+        bufport[received_port_len]=0;
+        
+        ci.received_host.s = val;
+        ci.received_host.len = port - val - 1;
+        LM_DBG("Setting received host in search to [%.*s]\n", ci.received_host.len, ci.received_host.s);
+        ci.received_port = atoi(bufport);
+        LM_DBG("Setting received port in search to %d\n", ci.received_port);
+        ci.received_proto = received_proto;
+        LM_DBG("Setting received proto in search to %d\n", ci.received_proto);
+        ci.searchflag = (1 << SEARCH_RECEIVED);
+    } else {
+        LM_DBG("Contact in NOTIFY does not have an alias....\n");
+    }
+
+    if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //contact does not exist
+        if (contact_state == STATE_TERMINATED) {
+            LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s);
+            ret = RESULT_CONTACTS_FOUND;
+            goto done;
+        }
+        LM_WARN("This contact: <%.*s> is in state active and is not in usrloc - must be another contact on a different P so going to ignore\n", contact_uri.len, contact_uri.s);
+        //		LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now);
+        //		if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) {
+        //			LM_ERR("Failed inserting new pcontact\n");
+        //			ret = RESULT_ERROR;
+        //			goto done;
+        //		} else {
+        //			//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
+        //			LM_DBG("registering for UL callback\n");
+        //			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
+        //		}
+    } else {//contact exists
+        if (contact_state == STATE_TERMINATED) {
+            //delete contact
+            LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
+            if (ul.delete_pcontact(_d, pcontact) != 0) {
+                LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s);
+            }
+            /*TODO_LATEST - put this back */
+        } else {//state is active
+            //update this contact
+            LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s,
+                    pcontact->expires,
+                    expires,
+                    expires - local_time_now);
+            if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
+                LM_ERR("failed to update pcscf contact\n");
+                ret = RESULT_ERROR;
+                goto done;
+            }
+            pcontact->expires = expires;
+        }
+    }
+
+done:
+    ul.unlock_udomain(_d, &puri.host, puri.port_no, puri.proto);
+    return ret;
+}
 
 int reginfo_parse_state(char * s) {
-	if (s == NULL) {
-		return STATE_UNKNOWN;
-	}
-	switch (strlen(s)) {
-		case 6:
-			if (strncmp(s, "active", 6) ==  0) return STATE_ACTIVE;
-			break;
-		case 10:
-			if (strncmp(s, "terminated", 10) ==  0) return STATE_TERMINATED;
-			break;
-		default:
-			LM_ERR("Unknown State %s\n", s);
-			return STATE_UNKNOWN;
-	}
-	LM_ERR("Unknown State %s\n", s);
-	return STATE_UNKNOWN;
+    if (s == NULL) {
+        return STATE_UNKNOWN;
+    }
+    switch (strlen(s)) {
+        case 6:
+            if (strncmp(s, "active", 6) == 0) return STATE_ACTIVE;
+            break;
+        case 10:
+            if (strncmp(s, "terminated", 10) == 0) return STATE_TERMINATED;
+            break;
+        default:
+            LM_ERR("Unknown State %s\n", s);
+            return STATE_UNKNOWN;
+    }
+    LM_ERR("Unknown State %s\n", s);
+    return STATE_UNKNOWN;
 }
 
 int reginfo_parse_event(char * s) {
-	if (s == NULL) {
-		return EVENT_UNKNOWN;
-	}
-	switch (strlen(s)) {
-		case 7:
-			if (strncmp(s, "created", 7) ==  0) return EVENT_CREATED;
-			if (strncmp(s, "expired", 7) ==  0) return EVENT_EXPIRED;
-			break;
-		case 9:
-			if (strncmp(s, "refreshed", 9) ==  0) return EVENT_CREATED;
-			break;
-		case 10:
-			if (strncmp(s, "registered", 10) ==  0) return EVENT_REGISTERED;
-			if (strncmp(s, "terminated", 10) ==  0) return EVENT_TERMINATED;
-			break;
-	    case 11:
-			if (strncmp(s, "deactivated", 11) ==  0) return EVENT_DEACTIVATED;
-			break;
-		case 12:
-			if (strncmp(s, "unregistered", 12) ==  0) return EVENT_UNREGISTERED;
-			break;
-		default:
-			LM_ERR("Unknown Event %s\n", s);
-			return EVENT_UNKNOWN;
-	}
-	LM_ERR("Unknown Event %s\n", s);
-	return EVENT_UNKNOWN;
+    if (s == NULL) {
+        return EVENT_UNKNOWN;
+    }
+    switch (strlen(s)) {
+        case 7:
+            if (strncmp(s, "created", 7) == 0) return EVENT_CREATED;
+            if (strncmp(s, "expired", 7) == 0) return EVENT_EXPIRED;
+            break;
+        case 9:
+            if (strncmp(s, "refreshed", 9) == 0) return EVENT_CREATED;
+            break;
+        case 10:
+            if (strncmp(s, "registered", 10) == 0) return EVENT_REGISTERED;
+            if (strncmp(s, "terminated", 10) == 0) return EVENT_TERMINATED;
+            break;
+        case 11:
+            if (strncmp(s, "deactivated", 11) == 0) return EVENT_DEACTIVATED;
+            break;
+        case 12:
+            if (strncmp(s, "unregistered", 12) == 0) return EVENT_UNREGISTERED;
+            break;
+        default:
+            LM_ERR("Unknown Event %s\n", s);
+            return EVENT_UNKNOWN;
+    }
+    LM_ERR("Unknown Event %s\n", s);
+    return EVENT_UNKNOWN;
 }
 
 xmlNodePtr xmlGetNodeByName(xmlNodePtr parent, const char *name) {
-	xmlNodePtr cur = parent;
-	xmlNodePtr match = NULL;
-	while (cur) {
-		if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0)
-			return cur;
-		match = xmlGetNodeByName(cur->children, name);
-		if (match)
-			return match;
-		cur = cur->next;
-	}
-	return NULL;
+    xmlNodePtr cur = parent;
+    xmlNodePtr match = NULL;
+    while (cur) {
+        if (xmlStrcasecmp(cur->name, (unsigned char*) name) == 0)
+            return cur;
+        match = xmlGetNodeByName(cur->children, name);
+        if (match)
+            return match;
+        cur = cur->next;
+    }
+    return NULL;
 }
 
 char * xmlGetAttrContentByName(xmlNodePtr node, const char *name) {
-	xmlAttrPtr attr = node->properties;
-	while (attr) {
-		if (xmlStrcasecmp(attr->name, (unsigned char*)name) == 0)
-			return (char*)xmlNodeGetContent(attr->children);
-		attr = attr->next;
-	}
-	return NULL;
+    xmlAttrPtr attr = node->properties;
+    while (attr) {
+        if (xmlStrcasecmp(attr->name, (unsigned char*) name) == 0)
+            return (char*) xmlNodeGetContent(attr->children);
+        attr = attr->next;
+    }
+    return NULL;
 }
 
 int process_body(struct sip_msg* msg, str notify_body, udomain_t * domain) {
-	xmlDocPtr doc= NULL;
-	xmlNodePtr doc_root = NULL, registrations = NULL, contacts = NULL, uris = NULL;
-	str aor = {0, 0};
-	str callid = {0, 0};
-	str contact_uri = {0, 0};
-	str received = {0,0};
-	str path = {0,0};
-	str user_agent = {0, 0};
-	int reg_state, contact_state, event, expires, result, final_result = RESULT_ERROR;
-	char * expires_char,  * cseq_char;
-	int cseq = 0;
-	pv_elem_t *presentity_uri_pv;
-	
-	doc = xmlParseMemory(notify_body.s, notify_body.len);
-	if(doc== NULL)  {
-		LM_ERR("Error while parsing the xml body message, Body is:\n%.*s\n",
-			notify_body.len, notify_body.s);
-		return -1;
-	}
-	doc_root = xmlGetNodeByName(doc->children, "reginfo");
-	if(doc_root == NULL) {
-		LM_ERR("while extracting the reginfo node\n");
-		goto error;
-	}
-	registrations = doc_root->children;
-	while (registrations) {
-		/* Only process registration sub-items */
-		if (xmlStrcasecmp(registrations->name, BAD_CAST "registration") != 0)
-			goto next_registration;
-		reg_state = reginfo_parse_state(xmlGetAttrContentByName(registrations, "state"));
-		if (reg_state == STATE_UNKNOWN) {
-			LM_ERR("No state for this registration!\n");		
-			goto next_registration;
-		}
-		aor.s = xmlGetAttrContentByName(registrations, "aor");
-		if (aor.s == NULL) {
-			LM_ERR("No AOR for this registration!\n");		
-			goto next_registration;
-		}
-		aor.len = strlen(aor.s);
-		LM_DBG("AOR %.*s has reg_state \"%d\"\n", aor.len, aor.s, reg_state);
-		
-		if (reg_state == STATE_TERMINATED) {
-		    //TODO we if there is a IMPU record state here we should delete all contacts associated to it
-		    //Right now we do it go through all the contacts
-		    LM_DBG("AOR %.*s is in state terminated so unsubscribing from reginfo\n", aor.len, aor.s);
-		    if(pv_parse_format(&aor, &presentity_uri_pv)<0) {
-			    LM_ERR("wrong format[%.*s] - failed unsubscribing to reginfo\n",aor.len, aor.s);
-		    }
-		    reginfo_subscribe_real(msg, presentity_uri_pv, 0, 0);
-		    pv_elem_free_all(presentity_uri_pv);
-		}
-		
-		/* Now lets process the Contact's from this Registration: */
-		contacts = registrations->children;
-		while (contacts) {
-			if (xmlStrcasecmp(contacts->name, BAD_CAST "contact") != 0)
-				goto next_contact;
-			callid.s = xmlGetAttrContentByName(contacts, "callid");
-			if (callid.s == NULL) {
-				LM_DBG("No Call-ID for this contact!\n");		
-				callid.len = 0;
-			} else {
-				callid.len = strlen(callid.s);
-				LM_DBG("contact has callid <%.*s>\n", callid.len, callid.s);		
-			}	
-			
-			received.s = xmlGetAttrContentByName(contacts, "received");
-			if (received.s == NULL) {
-				LM_DBG("No received for this contact!\n");
-				received.len = 0;
-			} else {
-				received.len = strlen(received.s);
-				LM_DBG("contact has received <%.*s>\n", received.len, received.s);
-			}
-
-			path.s = xmlGetAttrContentByName(contacts, "path");	
-			if (path.s == NULL) {
-				LM_DBG("No path for this contact!\n");
-				path.len = 0;
-			} else {
-				path.len = strlen(path.s);
-				LM_DBG("contact has path <%.*s>\n", path.len, path.s);
-			}
-
-			user_agent.s = xmlGetAttrContentByName(contacts, "user_agent");
-			if (user_agent.s == NULL) {
-				LM_DBG("No user_agent for this contact!\n");
-				user_agent.len = 0;
-			} else {
-				user_agent.len = strlen(user_agent.s);
-				LM_DBG("contact has user_agent <%.*s>\n", user_agent.len, user_agent.s);
-			}
-			event = reginfo_parse_event(xmlGetAttrContentByName(contacts, "event"));
-			if (event == EVENT_UNKNOWN) {
-				LM_ERR("No event for this contact - going to next contact!\n");		
-				goto next_contact;
-			}
-			expires_char = xmlGetAttrContentByName(contacts, "expires");
-			if (expires_char == NULL) {
-				LM_ERR("No expires for this contact - going to next contact!\n");		
-				goto next_contact;
-			}
-			expires = atoi(expires_char);
-			if (expires < 0) {
-				LM_ERR("No valid expires for this contact - going to next contact!\n");		
-				goto next_contact;
-			}
-			
-			contact_state = reginfo_parse_state(xmlGetAttrContentByName(contacts, "state"));
-			if (contact_state == STATE_UNKNOWN) {
-			    LM_ERR("No state for this contact - going to next contact!\n");		
-			    goto next_contact;
-			} 
-			
-			LM_DBG("Contact state %d: Event \"%d\", expires %d\n", contact_state, event, expires);
-
-			
-			
-			cseq_char = xmlGetAttrContentByName(contacts, "cseq");
-			if (cseq_char == NULL) {
-				LM_DBG("No cseq for this contact!\n");		
-			} else {
-				cseq = atoi(cseq_char);
-				if (cseq < 0) {
-					LM_DBG("No valid cseq for this contact!\n");		
-				}
-			}
-
-			/* Now lets process the URI's from this Contact: */
-			uris = contacts->children;
-			while (uris) {
-				if (xmlStrcasecmp(uris->name, BAD_CAST "uri") != 0)
-					goto next_uri;
-				contact_uri.s = (char*)xmlNodeGetContent(uris);	
-				if (contact_uri.s == NULL) {
-					LM_ERR("No URI for this contact - going to next registration!\n");		
-					goto next_registration;
-				}
-				contact_uri.len = strlen(contact_uri.s);
-				LM_DBG("Contact: %.*s\n",
-					contact_uri.len, contact_uri.s);
-
-				/* Add to Usrloc: */
-				result = process_contact(domain, expires, contact_uri, 0/*we don't have the recv ip*/, 0 /*we don't have the recv port*/, contact_state);
-
-				/* Process the result */
-				if (final_result != RESULT_CONTACTS_FOUND) final_result = result;
+    xmlDocPtr doc = NULL;
+    xmlNodePtr doc_root = NULL, registrations = NULL, contacts = NULL, uris = NULL;
+    str aor = {0, 0};
+    str callid = {0, 0};
+    str contact_uri = {0, 0};
+    str received = {0, 0};
+    str path = {0, 0};
+    str user_agent = {0, 0};
+    int reg_state, contact_state, event, expires, result, final_result = RESULT_ERROR;
+    char * expires_char, * cseq_char;
+    int cseq = 0;
+    pv_elem_t *presentity_uri_pv;
+
+    doc = xmlParseMemory(notify_body.s, notify_body.len);
+    if (doc == NULL) {
+        LM_ERR("Error while parsing the xml body message, Body is:\n%.*s\n",
+                notify_body.len, notify_body.s);
+        return -1;
+    }
+    doc_root = xmlGetNodeByName(doc->children, "reginfo");
+    if (doc_root == NULL) {
+        LM_ERR("while extracting the reginfo node\n");
+        goto error;
+    }
+    registrations = doc_root->children;
+    while (registrations) {
+        /* Only process registration sub-items */
+        if (xmlStrcasecmp(registrations->name, BAD_CAST "registration") != 0)
+            goto next_registration;
+        reg_state = reginfo_parse_state(xmlGetAttrContentByName(registrations, "state"));
+        if (reg_state == STATE_UNKNOWN) {
+            LM_ERR("No state for this registration!\n");
+            goto next_registration;
+        }
+        aor.s = xmlGetAttrContentByName(registrations, "aor");
+        if (aor.s == NULL) {
+            LM_ERR("No AOR for this registration!\n");
+            goto next_registration;
+        }
+        aor.len = strlen(aor.s);
+        LM_DBG("AOR %.*s has reg_state \"%d\"\n", aor.len, aor.s, reg_state);
+
+        if (reg_state == STATE_TERMINATED) {
+            //TODO we if there is a IMPU record state here we should delete all contacts associated to it
+            //Right now we do it go through all the contacts
+
+            LM_DBG("AOR %.*s is in state terminated so unsubscribing from reginfo\n", aor.len, aor.s);
+            //we return a successful result here even if no contacts
+            final_result = RESULT_TERMINATED_SUCCESS;
+
+            if (pv_parse_format(&aor, &presentity_uri_pv) < 0) {
+                LM_ERR("wrong format[%.*s] - failed unsubscribing to reginfo\n", aor.len, aor.s);
+            }
+            reginfo_subscribe_real(msg, presentity_uri_pv, 0, 0);
+            pv_elem_free_all(presentity_uri_pv);
+        }
+
+        /* Now lets process the Contact's from this Registration: */
+        contacts = registrations->children;
+        while (contacts) {
+            if (xmlStrcasecmp(contacts->name, BAD_CAST "contact") != 0)
+                goto next_contact;
+            callid.s = xmlGetAttrContentByName(contacts, "callid");
+            if (callid.s == NULL) {
+                LM_DBG("No Call-ID for this contact!\n");
+                callid.len = 0;
+            } else {
+                callid.len = strlen(callid.s);
+                LM_DBG("contact has callid <%.*s>\n", callid.len, callid.s);
+            }
+
+            received.s = xmlGetAttrContentByName(contacts, "received");
+            if (received.s == NULL) {
+                LM_DBG("No received for this contact!\n");
+                received.len = 0;
+            } else {
+                received.len = strlen(received.s);
+                LM_DBG("contact has received <%.*s>\n", received.len, received.s);
+            }
+
+            path.s = xmlGetAttrContentByName(contacts, "path");
+            if (path.s == NULL) {
+                LM_DBG("No path for this contact!\n");
+                path.len = 0;
+            } else {
+                path.len = strlen(path.s);
+                LM_DBG("contact has path <%.*s>\n", path.len, path.s);
+            }
+
+            user_agent.s = xmlGetAttrContentByName(contacts, "user_agent");
+            if (user_agent.s == NULL) {
+                LM_DBG("No user_agent for this contact!\n");
+                user_agent.len = 0;
+            } else {
+                user_agent.len = strlen(user_agent.s);
+                LM_DBG("contact has user_agent <%.*s>\n", user_agent.len, user_agent.s);
+            }
+            event = reginfo_parse_event(xmlGetAttrContentByName(contacts, "event"));
+            if (event == EVENT_UNKNOWN) {
+                LM_ERR("No event for this contact - going to next contact!\n");
+                goto next_contact;
+            }
+            expires_char = xmlGetAttrContentByName(contacts, "expires");
+            if (expires_char == NULL) {
+                LM_ERR("No expires for this contact - going to next contact!\n");
+                goto next_contact;
+            }
+            expires = atoi(expires_char);
+            if (expires < 0) {
+                LM_ERR("No valid expires for this contact - going to next contact!\n");
+                goto next_contact;
+            }
+
+            contact_state = reginfo_parse_state(xmlGetAttrContentByName(contacts, "state"));
+            if (contact_state == STATE_UNKNOWN) {
+                LM_ERR("No state for this contact - going to next contact!\n");
+                goto next_contact;
+            }
+
+            LM_DBG("Contact state %d: Event \"%d\", expires %d\n", contact_state, event, expires);
+
+
+
+            cseq_char = xmlGetAttrContentByName(contacts, "cseq");
+            if (cseq_char == NULL) {
+                LM_DBG("No cseq for this contact!\n");
+            } else {
+                cseq = atoi(cseq_char);
+                if (cseq < 0) {
+                    LM_DBG("No valid cseq for this contact!\n");
+                }
+            }
+
+            /* Now lets process the URI's from this Contact: */
+            uris = contacts->children;
+            while (uris) {
+                if (xmlStrcasecmp(uris->name, BAD_CAST "uri") != 0)
+                    goto next_uri;
+                contact_uri.s = (char*) xmlNodeGetContent(uris);
+                if (contact_uri.s == NULL) {
+                    LM_ERR("No URI for this contact - going to next registration!\n");
+                    goto next_registration;
+                }
+                contact_uri.len = strlen(contact_uri.s);
+                LM_DBG("Contact: %.*s\n",
+                        contact_uri.len, contact_uri.s);
+
+                /* Add to Usrloc: */
+                result = process_contact(domain, expires, contact_uri, contact_state);
+
+                /* Process the result */
+                if (final_result != RESULT_CONTACTS_FOUND) final_result = result;
 next_uri:
-				uris = uris->next;
-			}
+                uris = uris->next;
+            }
 next_contact:
-			contacts = contacts->next;
-		}
-		
+            contacts = contacts->next;
+        }
+
 next_registration:
-		// if (ul_record) ul.release_urecord(ul_record);		
-		/* Unlock the domain for this AOR: */
-		//if (aor_key.len > 0)
-		//	ul.unlock_udomain(domain, &aor_key);
+        // if (ul_record) ul.release_urecord(ul_record);		
+        /* Unlock the domain for this AOR: */
+        //if (aor_key.len > 0)
+        //	ul.unlock_udomain(domain, &aor_key);
 
-		registrations = registrations->next;
-	}
+        registrations = registrations->next;
+    }
 error:
-	/* Free the XML-Document */
-    	if(doc) xmlFreeDoc(doc);
-	return final_result;
+    /* Free the XML-Document */
+    if (doc) xmlFreeDoc(doc);
+    return final_result;
 }
 
+int reginfo_handle_notify(struct sip_msg* msg, char* domain, char* s2) {
+
+    LM_DBG("Handling notify\n");
+    str body;
+    int result = 1;
 
+    /* If not done yet, parse the whole message now: */
+    if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
+        LM_ERR("Error parsing headers\n");
+        return -1;
+    }
+    if (get_content_length(msg) == 0) {
+        LM_DBG("Content length = 0\n");
+        /* No Body? Then there is no published information available, which is ok. */
+        return 1;
+    } else {
+        body.s = get_body(msg);
+        if (body.s == NULL) {
+            LM_ERR("cannot extract body from msg\n");
+            return -1;
+        }
+        body.len = get_content_length(msg);
+    }
 
-int reginfo_handle_notify(struct sip_msg* msg, char* domain, char* s2) {
-	
-	LM_DBG("Handling notify\n");
-	str body;
-	int result = 1;
-
-  	/* If not done yet, parse the whole message now: */
-  	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
-  		LM_ERR("Error parsing headers\n");
-  		return -1;
-  	}
-	if (get_content_length(msg) == 0) {
-   		LM_DBG("Content length = 0\n");
-		/* No Body? Then there is no published information available, which is ok. */
-   		return 1;
-   	} else {
-   		body.s=get_body(msg);
-   		if (body.s== NULL) {
-   			LM_ERR("cannot extract body from msg\n");
-   			return -1;
-   		}
-   		body.len = get_content_length(msg);
-   	}
-
-	LM_DBG("Body is %.*s\n", body.len, body.s);
-	
-	result = process_body(msg, body, (udomain_t*)domain);
-
-	
-	return result;
+    LM_DBG("Body is %.*s\n", body.len, body.s);
+
+    result = process_body(msg, body, (udomain_t*) domain);
+
+
+    return result;
 }
 

+ 0 - 112
modules/ims_registrar_pcscf/reg_mod.c

@@ -69,7 +69,6 @@
 #include "reg_mod.h"
 #include "save.h"
 #include "service_routes.h"
-#include "lookup.h"
 MODULE_VERSION
 
 usrloc_api_t ul;						/**!< Structure containing pointers to usrloc functions*/
@@ -114,19 +113,14 @@ static int w_follows_service_routes(struct sip_msg* _m, char* _d, char* _foo);
 static int w_force_service_routes(struct sip_msg* _m, char* _d, char* _foo);
 static int w_is_registered(struct sip_msg* _m, char* _d, char* _foo);
 static int w_reginfo_handle_notify(struct sip_msg* _m, char* _d, char* _foo);
-static int w_unregister(struct sip_msg* _m, char* _d, char* _aor, char* _received_host, char* _received_port);
 
 static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri);
 static int w_assert_called_identity(struct sip_msg* _m, char* _d, char* _foo);
 
-static int w_lookup_transport(struct sip_msg* _m, char* _d, char* _uri);
-
 /*! \brief Fixup functions */
 static int domain_fixup(void** param, int param_no);
-static int domain_uri_fixup(void** param, int param_no);
 static int save_fixup2(void** param, int param_no);
 static int assert_identity_fixup(void ** param, int param_no);
-static int unregister_fixup(void ** param, int param_no);
 
 /* Pseudo-Variables */
 static int pv_get_asserted_identity_f(struct sip_msg *, pv_param_t *, pv_value_t *);
@@ -152,10 +146,6 @@ static cmd_export_t cmds[] = {
 	{"pcscf_assert_identity",       (cmd_function)w_assert_identity,        2,  	assert_identity_fixup,  0,REQUEST_ROUTE },
 	{"pcscf_assert_called_identity",(cmd_function)w_assert_called_identity, 1,      assert_identity_fixup,  0,ONREPLY_ROUTE },
 	{"reginfo_handle_notify",       (cmd_function)w_reginfo_handle_notify,  1,      domain_fixup,           0,REQUEST_ROUTE},
-        {"lookup_transport",		(cmd_function)w_lookup_transport,       1,      domain_fixup,           0,REQUEST_ROUTE|FAILURE_ROUTE},
-        {"lookup_transport",		(cmd_function)w_lookup_transport,       2,      domain_uri_fixup,       0,REQUEST_ROUTE|FAILURE_ROUTE},
-        {"pcscf_unregister",		(cmd_function)w_unregister,		4,      unregister_fixup,       0,ANY_ROUTE},
-	
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -365,23 +355,6 @@ static int domain_fixup(void** param, int param_no)
 	return 0;
 }
 
-static int domain_uri_fixup(void** param, int param_no)
-{
-	udomain_t* d;
-
-	if (param_no == 1) {
-		if (ul.register_udomain((char*)*param, &d) < 0) {
-			LM_ERR("failed to register domain\n");
-			return E_UNSPEC;
-		}
-		*param = (void*)d;
-	} else {
-            fixup_var_pve_str_12(param, param_no);
-        }
-        
-	return 0;
-}
-
 /*! \brief
  * Fixup for "save" function - both domain and flags
  */
@@ -431,21 +404,6 @@ static int w_save(struct sip_msg* _m, char* _d, char* _cflags)
 	return save(_m, (udomain_t*)_d, ((int)(unsigned long)_cflags));
 }
 
-/*! \brief
- * Wrapper to lookup_transport(location)
- */
-static int w_lookup_transport(struct sip_msg* _m, char* _d, char* _uri)
-{
-	str uri = {0};
-	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0))
-	{
-		LM_ERR("invalid uri parameter\n");
-		return -1;
-	}
-
-	return lookup_transport(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
-}
-
 static int w_save_pending(struct sip_msg* _m, char* _d, char* _cflags)
 {
 	return save_pending(_m, (udomain_t*)_d);
@@ -489,76 +447,6 @@ static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri)
 	return assert_identity( _m, (udomain_t*)_d, identity);
 }
 
-/*! \brief
- * Fixup for "assert_identity" function - both domain and URI to be asserted
- */
-static int unregister_fixup(void ** param, int param_no) {
-	if (param_no == 1) {
-		return domain_fixup(param,param_no);
-	} else {
-		pv_elem_t *model=NULL;
-		str s;
-
-		/* convert to str */
-		s.s = (char*)*param;
-		s.len = strlen(s.s);
-
-		model = NULL;
-		if(s.len==0) {
-			LM_ERR("no param!\n");
-			return E_CFG;
-		}
-		if(pv_parse_format(&s, &model)<0 || model==NULL) {
-			LM_ERR("wrong format [%s]!\n", s.s);
-			return E_CFG;
-		}
-		*param = (void*)model;
-		return 0;
-	}
-	return E_CFG;
-}
-
-
-static int w_unregister(struct sip_msg* _m, char* _d, char* _aor, char* _received_host, char* _received_port) {
-	pv_elem_t *model;
-	str aor;
-	str received_host;
-	str received_port;
-	int port = 0;
-
-	if ((_aor == NULL) || (_received_host == NULL) || (_received_port == NULL)) {
-		LM_ERR("error - bad parameters\n");
-		return -1;
-	}
-
-	model = (pv_elem_t*)_aor;
-	if (pv_printf_s(_m, model, &aor)<0) {
-		LM_ERR("error - cannot print the format\n");
-		return -1;
-	}
-	LM_DBG("URI: %.*s\n", aor.len, aor.s);
-
-	model = (pv_elem_t*)_received_host;
-	if (pv_printf_s(_m, model, &received_host)<0) {
-		LM_ERR("error - cannot print the format\n");
-		return -1;
-	}
-	LM_DBG("Received-Host: %.*s\n", received_host.len, received_host.s);
-
-	model = (pv_elem_t*)_received_port;
-	if (pv_printf_s(_m, model, &received_port)<0) {
-		LM_ERR("error - cannot print the format\n");
-		return -1;
-	}
-	LM_DBG("Received-Port: %.*s\n", received_port.len, received_port.s);
-	if (str2sint(&received_port, &port) != 0) {
-		LM_ERR("error - cannot convert %.*s to an int!\n", received_port.len, received_port.s);
-		return -1;
-	}
-
-	return unregister((udomain_t*)_d, &aor, &received_host, port);
-}
-
 static int w_assert_called_identity(struct sip_msg* _m, char* _d, char* _foo) {
 	return assert_called_identity( _m, (udomain_t*)_d);
 }

+ 32 - 16
modules/ims_registrar_pcscf/save.c

@@ -123,6 +123,7 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 	pcontact_t* pcontact;
 	char srcip[50];
 	int_str val;
+        unsigned short port;
 
 	pcscf_act_time();
 	local_time_now = time_now;
@@ -155,6 +156,7 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 				ci.received_host.s = 0;
 				ci.received_port = 0;
 				ci.received_proto = 0;
+                                ci.searchflag = 1<<SEARCH_RECEIVED;
 
 				// Received Info: First try AVP, otherwise simply take the source of the request:
 				memset(&val, 0, sizeof(int_str));
@@ -179,9 +181,12 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 				// Set to default, if not set:
 				if (ci.received_port == 0) ci.received_port = 5060;
 
-				
-				ul.lock_udomain(_d, &c->uri, &ci.received_host, ci.received_port);
-				if (ul.get_pcontact(_d, &c->uri, &ci.received_host, ci.received_port, &pcontact) != 0) { //need to insert new contact
+				port = puri.port_no?puri.port_no:5060;
+                                ci.via_host = puri.host;
+                                ci.via_port = port;
+                                ci.via_prot = puri.proto;
+				ul.lock_udomain(_d, &puri.host, port, puri.proto);
+				if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
 					if ((expires-local_time_now)<=0) { //remove contact - de-register
 						LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
 						goto next_contact;
@@ -201,9 +206,10 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 					LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state));
 					if ((expires-local_time_now)<=0) { //remove contact - de-register
 						LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s);
-						if (ul.delete_pcontact(_d, &c->uri, &ci.received_host, ci.received_port, pcontact) != 0) {
-							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
-						}
+//						if (ul.delete_pcontact(_d, &c->uri, &ci.received_host, ci.received_port, pcontact) != 0) {
+//							LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s);
+//						}
+                                                //TODO_LATEST replace above
 					} else { //update contact
 						LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s,
 								pcontact->expires-local_time_now,
@@ -216,7 +222,7 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 					}
 				}
 next_contact:
-				ul.unlock_udomain(_d, &c->uri, &ci.received_host, ci.received_port);
+				ul.unlock_udomain(_d, &puri.host, port, puri.proto);
 			}
 	}
 	return 1;
@@ -226,7 +232,7 @@ error:
 
 /**
  * Save contact based on REGISTER request. this will be a pending save, until we receive response
- * from SCSCF. If no response after pending_timeout seconds, the contacts is removed
+ * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE
  */
 int save_pending(struct sip_msg* _m, udomain_t* _d) {
 	contact_body_t* cb = 0;
@@ -234,22 +240,25 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 	pcontact_t* pcontact;
 	contact_t* c;
 	struct pcontact_info ci;
+        struct via_body* vb;
+        unsigned short port, proto;
 	int_str val;
 	struct sip_uri parsed_received;
 	char srcip[50];
 
 	memset(&ci, 0, sizeof(struct pcontact_info));
+        
+        vb = cscf_get_ue_via(_m);
+        port = vb->port?vb->port:5060;
+        proto = vb->proto;
 
 	cb = cscf_parse_contacts(_m);
 	if (!cb || (!cb->contacts)) {
 		LM_ERR("No contact headers\n");
 		goto error;
 	}
-	c = cb->contacts;
-	if (!c) {
-		LM_ERR("no valid contact to register\n");
-		goto error;
-	}
+        
+        c = cb->contacts;
 	//TODO: need support for multiple contacts - currently assume one contact
 	//make sure this is not a de-registration
 	int expires_hdr = cscf_get_expires_hdr(_m, 0);
@@ -263,6 +272,7 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 			return 1;
 		}
 	}
+        
 	pcscf_act_time();
 	int local_time_now = time_now;
 	int expires = calc_contact_expires(c, expires_hdr, local_time_now);
@@ -270,9 +280,14 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 		LM_DBG("not doing pending reg on de-registration\n");
 		return 1;
 	}
+        LM_DBG("Save Pending");
 	LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now);
 
 	/*populate CI with bare minimum*/
+        ci.via_host = vb->host;
+        ci.via_port = port;
+        ci.via_prot = proto;
+        ci.aor = c->uri;
 	ci.num_public_ids=0;
 	ci.num_service_routes=0;
 	ci.expires=local_time_now + pending_reg_expires;
@@ -300,13 +315,14 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 		ci.received_host.s = srcip;
 		ci.received_port = _m->rcv.src_port;
 		ci.received_proto = _m->rcv.proto;
+                
 	}
 	// Set to default, if not set:
 	if (ci.received_port == 0)
 		ci.received_port = 5060;
 
-	ul.lock_udomain(_d, &c->uri, &ci.received_host, ci.received_port);
-	if (ul.get_pcontact(_d, &c->uri, &ci.received_host, ci.received_port, &pcontact) != 0) { //need to insert new contact
+	ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
+	if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
 		LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
 		if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) {
 			LM_ERR("Failed inserting new pcontact\n");
@@ -317,7 +333,7 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
 	} else { //contact already exists - update
 		LM_DBG("Contact already exists - not doing anything for now\n");
 	}
-	ul.unlock_udomain(_d, &c->uri, &ci.received_host, ci.received_port);
+	ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
 
 	return 1;
 

+ 1 - 1
modules/ims_registrar_pcscf/save.h

@@ -55,7 +55,7 @@
  */
 int save(struct sip_msg* _m, udomain_t* _d, int _cflags);
 int save_pending(struct sip_msg* _m, udomain_t* _d);
-// int unregister(struct sip_msg* _m, char* _d, char* _uri);
+int unregister(struct sip_msg* _m, char* _d, char* _uri);
 struct sip_msg* get_request_from_reply(struct sip_msg* reply);
 
 

+ 143 - 144
modules/ims_registrar_pcscf/service_routes.c

@@ -23,6 +23,8 @@
 #include "service_routes.h"
 #include "reg_mod.h"
 #include "save.h"
+#include "../../parser/parse_via.h"
+#include "../../parser/msg_parser.h"
 #include "../../data_lump.h"
 #include "../../lib/ims/ims_getters.h"
 
@@ -164,111 +166,115 @@ int checkcontact(struct sip_msg* _m, pcontact_t * c) {
  * (search only once per Request)
  */
 pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) {
-	ppublic_t * p;
-	contact_body_t *b = 0;
-	contact_t *ct;
-	str received_host = {0, 0};
-	char srcip[50];	
-
-	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
-			received_host.s = srcip;
-			
-	if (_m->id != current_msg_id) {
-		current_msg_id = _m->id;
-		c = NULL;
-
-		if (is_registered_fallback2ip == 2) {
-			LM_DBG("Searching in usrloc for %.*s:%i (Proto %i)\n",
-				received_host.len, received_host.s,
-				_m->rcv.src_port, _m->rcv.proto);
-
-			if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) {
-				LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
-			} else {
-				if (checkcontact(_m, c) != 0) {
-					c = NULL;
-				}
-			}
-		}
-
-		if (c == NULL) {
-			b = cscf_parse_contacts(_m);
-
-			if (b && b->contacts) {
-				for (ct = b->contacts; ct; ct = ct->next) {
-					if (ul.get_pcontact(_d, &ct->uri, &received_host, _m->rcv.src_port, &c) == 0) {
-						if (checkcontact(_m, c) != 0) {
-							c = NULL;
-						} else {
-							break;
-						}
-					}
-				}
-			} else {
-				LM_WARN("No contact-header found?!?\n");
-			}
-		}
-
-		if ((c == NULL) && (is_registered_fallback2ip == 1)) {
-			LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n");
-			received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
-			received_host.s = srcip;
-			if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) {
-				LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
-			} else {
-				if (checkcontact(_m, c) != 0) {
-					c = NULL;
-				}
-			}
-		}
-	}
-	asserted_identity = NULL;
-	registration_contact = NULL;
-	if (c) {
-		registration_contact = &c->contact_user;
-		p = c->head;
-		while (p) {
-			if (p->is_default == 1)
-				asserted_identity = &p->public_identity;
-			p = p->next;
-		}
-	}
-
-	return c;
-}
-
-pcontact_t * getContactP_from_via(struct sip_msg* _m, udomain_t* _d) {
-	ppublic_t * p;
-	struct via_body *vb;
-
-	vb = cscf_get_ue_via(_m);
-	if (!vb) {
-		LM_WARN("no via header.....strange!\n");
-		return NULL;
-	}
-
-	if (vb->port == 0)
-		vb->port = 5060;
-
-	if (_m->id != current_msg_id) {
-		current_msg_id = _m->id;
-		c = NULL;
-		LM_DBG("Looking for <%d://%.*s:%d>\n", vb->proto, vb->host.len, vb->host.s, vb->port);
-		if (ul.get_pcontact_by_src(_d, &vb->host, vb->port, vb->proto, &c) == 1)
-			LM_WARN("No entry in usrloc for %.*s:%i (Proto %i) found!\n", vb->host.len, vb->host.s, vb->port, vb->proto);
-	}
-
-	asserted_identity = NULL;
-	if (c) {
-		p = c->head;
-		while (p) {
-			if (p->is_default == 1)
-				asserted_identity = &p->public_identity;
-			p = p->next;
-		}
-	}
-
-	return c;
+    ppublic_t * p;
+    contact_body_t *b = 0;
+    contact_t *ct;
+    pcontact_info_t search_ci;
+    str received_host = {0, 0};
+    char srcip[50];
+    struct via_body *vb;
+    unsigned short port, proto;
+    str host;
+    sip_uri_t contact_uri;
+
+    b = cscf_parse_contacts(_m);
+
+    if (_m->first_line.type == SIP_REPLY && _m->contact && _m->contact->parsed && b->contacts) {
+        LM_DBG("This is a reply - to look for contact we favour the contact header above the via (b2bua)... if no contact we will use last via\n");
+        ct = b->contacts;
+        host = ct->uri;
+        if (parse_uri(ct->uri.s, ct->uri.len, &contact_uri) != 0) {
+            LM_WARN("Failed to parse contact [%.*s]\n", ct->uri.len, ct->uri.s);
+            return NULL;
+        }
+        host = contact_uri.host;
+        port = contact_uri.port_no ? contact_uri.port_no : 5060;
+        proto = contact_uri.proto;
+        if (proto == 0) {
+            LM_DBG("Contact protocol not specified - using received\n");
+            proto = _m->rcv.proto;
+        }
+    } else {
+        if (_m->first_line.type == SIP_REPLY)
+            LM_DBG("This is a reply but we are forced to use the via header\n");
+        else
+            LM_DBG("This is a request - using first via to find contact\n");
+
+        vb = cscf_get_ue_via(_m);
+        host = vb->host;
+        port = vb->port ? vb->port : 5060;
+        proto = vb->proto;
+    }
+
+    LM_DBG("searching for contact with host:port:proto contact [%d://%.*s:%d]\n", proto, host.len, host.s, port);
+
+    received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof (srcip));
+    received_host.s = srcip;
+
+//    if (_m->id != current_msg_id) {
+        current_msg_id = _m->id;
+        c = NULL;
+        search_ci.received_host.s = 0;
+        search_ci.received_host.len = 0;
+        search_ci.received_port = 0;
+        search_ci.received_proto = 0;
+        search_ci.searchflag = SEARCH_NORMAL;
+        search_ci.via_host = host;
+        search_ci.via_port = port;
+        search_ci.via_prot = proto;
+        search_ci.aor.s = 0;
+        search_ci.aor.len = 0;
+
+        if (c == NULL) {
+            b = cscf_parse_contacts(_m);
+
+            if (b && b->contacts) {
+                for (ct = b->contacts; ct; ct = ct->next) {
+                    search_ci.aor = ct->uri;
+                    if (ul.get_pcontact(_d, &search_ci, &c) == 0) {
+                        if (checkcontact(_m, c) != 0) {
+                            c = NULL;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            } else {
+                LM_WARN("No contact-header found?!?\n");
+            }
+        }
+
+        if ((c == NULL) && (is_registered_fallback2ip == 1)) {
+            LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n");
+            //			received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
+            //			received_host.s = srcip;
+            if (ul.get_pcontact(_d, &search_ci, &c) == 1) {
+                LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto);
+            } else {
+                if (checkcontact(_m, c) != 0) {
+                    c = NULL;
+                }
+            }
+        }
+//    }
+    asserted_identity = NULL;
+    registration_contact = NULL;
+    if (c) {
+        registration_contact = &c->contact_user;
+        p = c->head;
+        while (p) {
+            if (p->is_default == 1)
+                asserted_identity = &p->public_identity;
+            p = p->next;
+        }
+    }
+    
+//    LM_DBG("pcontact flag is [%d]\n", c->flags);
+//    if (c && (c->flags & (1<<FLAG_READFROMDB)) != 0) {
+//        LM_DBG("we have a contact that was read fresh from the DB....\n");
+//    }
+
+    return c;
 }
 
 /**
@@ -279,9 +285,12 @@ int check_service_routes(struct sip_msg* _m, udomain_t* _d) {
 	int i;
 	struct hdr_field *hdr;
 	rr_t *r;
-	char srcip[20];
-	str received_host;
-	pcontact_t * c = getContactP(_m, _d);
+//	char srcip[20];
+//	str received_host;
+	
+        struct via_body * vb;
+        unsigned short port;
+        unsigned short proto;
 	/* Contact not found => not following service-routes */
 	if (c == NULL) return -1;
 
@@ -290,11 +299,16 @@ int check_service_routes(struct sip_msg* _m, udomain_t* _d) {
 
 	LM_DBG("Got %i Route-Headers.\n", c->num_service_routes);
 
-	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
-	received_host.s = srcip;
+//	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
+//	received_host.s = srcip;
+        vb = cscf_get_ue_via(_m);
+        port = vb->port?vb->port:5060;
+        proto = vb->proto;
 	
 	/* Lock this record while working with the data: */
-	ul.lock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.lock_udomain(_d, &vb->host, port, proto);
+        
+        pcontact_t * c = getContactP(_m, _d);
 
 	/* Check the route-set: */
 	if (_m->route) {
@@ -366,12 +380,13 @@ int check_service_routes(struct sip_msg* _m, udomain_t* _d) {
 		if (c->num_service_routes > 0) goto error;
 	}
 	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.unlock_udomain(_d, &vb->host, port, proto);
 	return 1;
 error:
 	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.unlock_udomain(_d, &vb->host, port, proto);
 	return -1;
+    return 1;
 }
 
 static str route_start={"Route: <",8};
@@ -388,8 +403,11 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
 	struct lump* lmp = NULL;
 	char * buf;
 	pcontact_t * c = getContactP(_m, _d);
-	char srcip[20];
-	str received_host;
+//	char srcip[20];
+//	str received_host;
+        struct via_body* vb;
+        unsigned short port;
+        unsigned short proto;
 	
 	// Contact not found => not following service-routes
 	if (c == NULL) return -1;
@@ -397,6 +415,10 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
 	/* we need to be sure we have seen all HFs */
 	parse_headers(_m, HDR_EOH_F, 0);
 
+        vb = cscf_get_ue_via(_m);
+        port = vb->port?vb->port:5060;
+        proto = vb->proto;
+        
 	/* Save current buffer */
 	buf = _m->buf;
 
@@ -419,11 +441,11 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
 		_m->dst_uri.len = 0;
 	}
 	
-	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
-	received_host.s = srcip;
+//	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
+//	received_host.s = srcip;
 
 	/* Lock this record while working with the data: */
-	ul.lock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.lock_udomain(_d, &vb->host, port, proto);
 
 	if (c->num_service_routes > 0) {
 		/* Create anchor for new Route-Header: */
@@ -471,13 +493,14 @@ int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
 		}
 	}
 	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.unlock_udomain(_d, &vb->host, port, proto);
 	return 1;
 error:
 	/* Unlock domain */
-	ul.unlock_udomain(_d, &c->aor, &received_host, _m->rcv.src_port);
+	ul.unlock_udomain(_d, &vb->host, port, proto);
 	return -1;
 	
+    return 1;
 }
 
 /**
@@ -488,30 +511,6 @@ int is_registered(struct sip_msg* _m, udomain_t* _d) {
 	return -1;	
 }
 
-int unregister(udomain_t* _d, str * uri, str * received_host, int received_port) {
-	int result = -1;
-	struct pcontact * pcontact;
-	struct pcontact_info ci;
-    	memset(&ci, 0, sizeof (struct pcontact_info));
-
-	if (ul.get_pcontact(_d, uri, received_host, received_port, &pcontact) == 0) {
-		/* Lock this record while working with the data: */
-		ul.lock_udomain(_d, &pcontact->aor, received_host, received_port);
-
-		LM_DBG("Updating contact [%.*s]: setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s);
-
-		ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH;
-		ci.num_service_routes = 0;
-		if (ul.update_pcontact(_d, &ci, pcontact) == 0) result = 1;
-
-		// if (ul.delete_pcontact(_d, &pc->aor, received_host, received_port, pcontact) == 0) result = 1;
-
-		/* Unlock domain */
-		ul.unlock_udomain(_d, &pcontact->aor, received_host, received_port);
-	}
-	return result;
-}
-
 /**
  * Get the current asserted identity for the user
  */

+ 0 - 5
modules/ims_registrar_pcscf/service_routes.h

@@ -61,9 +61,4 @@ int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity);
  */
 int assert_called_identity(struct sip_msg* _m, udomain_t* _d);
 
-/**
- * Unregister a contact
- */
-int unregister(udomain_t* _d, str * uri, str * received_host, int received_port);
-
 #endif /* SERVICE_ROUTES_H */

+ 1 - 1
modules/ims_registrar_scscf/cxdx_avp.c

@@ -148,7 +148,7 @@ inline int cxdx_add_call_id(AAAMessage *msg, str data)
 	cxdx_add_avp(msg,data.s,data.len,
 		AVP_Call_Id,
 		AAA_AVP_FLAG_VENDOR_SPECIFIC,
-		0,
+		50,
 		AVP_DUPLICATE_DATA,
 		__FUNCTION__);
 }

+ 19 - 4
modules/ims_registrar_scscf/cxdx_callbacks.c

@@ -25,6 +25,7 @@
 #include "../../dprint.h"
 #include "../ims_usrloc_scscf/usrloc.h"
 #include "cxdx_avp.h"
+#include "registrar_notify.h"
 
 
 extern struct cdp_binds cdpb;
@@ -86,8 +87,15 @@ AAAMessage* cxdx_process_rtr(AAAMessage *rtr) {
             }
 	    
 	    for(i = 0; i < r->num_contacts; i++) {
-		LM_DBG("Expiring contact with AOR [%.*s]\n", r->newcontacts[i]->aor.len, r->newcontacts[i]->aor.s);
-		ul.expire_ucontact(r, r->newcontacts[i]);
+                LM_DBG("Deleting contact with AOR [%.*s]\n", r->newcontacts[i]->aor.len, r->newcontacts[i]->aor.s);
+                ul.lock_contact_slot_i(r->newcontacts[i]->sl);
+                r->newcontacts[i]->state = CONTACT_DELETE_PENDING;
+                if (r->shead) {
+                    //send NOTIFY to all subscribers of this IMPU.
+                    notify_subscribers(r);
+                }
+               r->newcontacts[i]->state = CONTACT_DELETED;
+                ul.unlock_contact_slot_i(r->newcontacts[i]->sl);
 	    }
 	    
 	    ul.unlock_udomain(udomain, &public_id);
@@ -105,8 +113,15 @@ AAAMessage* cxdx_process_rtr(AAAMessage *rtr) {
 		    }
 
 		    for(i = 0; i < r->num_contacts; i++) {
-			LM_DBG("Expiring contact with AOR [%.*s]\n", r->newcontacts[i]->aor.len, r->newcontacts[i]->aor.s);
-			ul.expire_ucontact(r, r->newcontacts[i]);
+			LM_DBG("Deleting contact with AOR [%.*s]\n", r->newcontacts[i]->aor.len, r->newcontacts[i]->aor.s);
+                        ul.lock_contact_slot_i(r->newcontacts[i]->sl);
+                        r->newcontacts[i]->state = CONTACT_DELETE_PENDING;
+                        if (r->shead) {
+                            //send NOTIFY to all subscribers of this IMPU.
+                            notify_subscribers(r);
+                        }
+                        r->newcontacts[i]->state = CONTACT_DELETED;
+                        ul.unlock_contact_slot_i(r->newcontacts[i]->sl);
 		    }
 
 		    ul.unlock_udomain(udomain, &public_id);

+ 1 - 0
modules/ims_registrar_scscf/cxdx_sar.c

@@ -63,6 +63,7 @@
 #include "regtime.h"
 #include "../../parser/hf.h"
 #include "../../lib/ims/ims_getters.h"
+#include "registrar_notify.h"
 
 extern struct cdp_binds cdpb;
 

+ 1 - 1
modules/ims_registrar_scscf/lookup.c

@@ -203,7 +203,7 @@ int lookup_path_to_contact(struct sip_msg* _m, char* contact_uri) {
     }
     LM_DBG("Looking up contact [%.*s]\n", s_contact_uri.len, s_contact_uri.s);
 
-    if (ul.get_ucontact(NULL, &s_contact_uri, 0, 0, 0, &contact) == 0) { //get_contact returns with lock
+    if (ul.get_ucontact(&s_contact_uri, 0, 0, 0, &contact) == 0) { //get_contact returns with lock
 
         if (!VALID_CONTACT(contact, act_time)) {
             LM_DBG("Contact is not valid...ignoring\n");

+ 7 - 0
modules/ims_registrar_scscf/reg_mod.c

@@ -162,6 +162,7 @@ int subscription_default_expires = 3600; /**< the default value for expires if n
 int subscription_min_expires = 10; /**< minimum subscription expiration time 		*/
 int subscription_max_expires = 1000000; /**< maximum subscription expiration time 		*/
 int subscription_expires_range = 0;
+int contact_expires_buffer_percentage = 10;     /**< percentage we expiry for contact we will substrace from reg response to UE */
 
 int notification_list_size_threshold = 0; /**Threshold for size of notification list after which a warning is logged */
 
@@ -258,6 +259,7 @@ static param_export_t params[] = {
     {"subscription_default_expires", INT_PARAM, &subscription_default_expires},
     {"subscription_min_expires", INT_PARAM, &subscription_min_expires},
     {"subscription_max_expires", INT_PARAM, &subscription_max_expires},
+    {"expires_buffer_percent", INT_PARAM, &contact_expires_buffer_percentage},
     {"ue_unsubscribe_on_dereg", INT_PARAM, &ue_unsubscribe_on_dereg},
     {"subscription_expires_range", INT_PARAM, &subscription_expires_range},
     {"user_data_always", INT_PARAM, &user_data_always},
@@ -320,6 +322,11 @@ static int mod_init(void) {
         LM_ERR("Unable to allocate memory for service route uri\n");
         return -1;
     }
+    
+    if (contact_expires_buffer_percentage < 0 || contact_expires_buffer_percentage > 90) {
+        LM_ERR("contact expires percentage not valid, must be >0 and <=90");
+        return -1;
+    }
 
     memcpy(scscf_serviceroute_uri_str.s, orig_prefix.s, orig_prefix.len);
     scscf_serviceroute_uri_str.len = orig_prefix.len;

+ 223 - 168
modules/ims_registrar_scscf/registrar_notify.c

@@ -436,7 +436,7 @@ error:
  * called to deliver new event into notification process
  * return 0 on success. anything else failure
  */
-int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int event_type, str *presentity_uri, str *watcher_contact) {
+int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact) {
 
     str content = {0, 0};
     impurecord_t* r;
@@ -453,8 +453,8 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int e
         case IMS_REGISTRAR_NONE:
             return 0;
         case IMS_REGISTRAR_SUBSCRIBE:
-            if (r_passed || c_passed || !presentity_uri || !watcher_contact || !_d) {
-                LM_ERR("this is a subscribe called from cfg file: r_passed and c_passed should both be zero and presentity_uri, watcher_contact and _d should be valid for a subscribe");
+            if (r_passed || !presentity_uri || !watcher_contact || !_d) {
+                LM_ERR("this is a subscribe called from cfg file: r_passed be zero and presentity_uri, watcher_contact and _d should be valid for a subscribe");
                 return 0;
             }
             LM_DBG("Event type is IMS REGISTRAR SUBSCRIBE about to get reginfo_full");
@@ -491,7 +491,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int e
 
             LM_DBG("About to ceate notification");
 
-            create_notifications(_d, r_passed, c_passed, presentity_uri, watcher_contact, content, event_type);
+            create_notifications(_d, r_passed, presentity_uri, watcher_contact, content, event_type);
             if (content.s) pkg_free(content.s);
             //            if (send_now) notification_timer(0, 0);
             return 0;
@@ -503,7 +503,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int e
         case IMS_REGISTRAR_CONTACT_REGISTERED:
         case IMS_REGISTRAR_CONTACT_REFRESHED:
         case IMS_REGISTRAR_CONTACT_EXPIRED:
-            if (!r_passed || !c_passed || presentity_uri || watcher_contact || _d) {
+            if (!r_passed || presentity_uri || watcher_contact || _d) {
                 LM_ERR("this is a contact change passed from ul callback: r_passed and c_passed should both be valid and presentity_uri, watcher_contact and _d should be 0 for ul callback");
                 return 0;
             }
@@ -536,7 +536,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int e
 
             LM_DBG("About to ceate notification");
 
-            create_notifications(_d, r_passed, c_passed, presentity_uri, watcher_contact, content, event_type);
+            create_notifications(_d, r_passed, presentity_uri, watcher_contact, content, event_type);
             if (content.s) pkg_free(content.s);
             //                        if (send_now) notification_timer(0, 0);
             return 1;
@@ -548,7 +548,22 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int e
     }
 }
 
-int process_contact(impurecord_t* presentity_impurecord, udomain_t * _d, int expires, str contact_uri, int contact_state) {
+int notify_subscribers(impurecord_t* impurecord) {
+    event_reg(0, impurecord, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0);
+    
+    return 0;
+}
+
+/*! Called to process a contact in a received publish document. No locks held when calling this function
+ * 
+ * @param subscription
+ * @param _d
+ * @param expires
+ * @param contact_uri
+ * @param contact_state
+ * @return 
+ */
+int process_contact(ims_subscription* subscription, udomain_t * _d, int expires, str contact_uri, int contact_state) {
 
     int ret = CSCF_RETURN_TRUE;
     int i, j;
@@ -556,8 +571,8 @@ int process_contact(impurecord_t* presentity_impurecord, udomain_t * _d, int exp
     struct ucontact* ucontact;
     str callid = {0, 0};
     str path = {0, 0};
-    ims_subscription* subscription = 0;
     impurecord_t* implicit_impurecord = 0;
+    get_act_time();
 
     //first get the subscription
     //then go through each implicit public identity (exclude the explicit identity)
@@ -565,48 +580,42 @@ int process_contact(impurecord_t* presentity_impurecord, udomain_t * _d, int exp
     //then get the contact for each implicit IMPU and delete if contact_state == STATE_TERMINATED
     //then get the contact for each explicit IMPU and delete if contact_state == STATE_TERMINATED
 
-    subscription = presentity_impurecord->s;
-    if (!subscription) {
-        LM_DBG("No subscriber info associated with <%.*s>, so no implicit IMPUs to process\n", presentity_impurecord->public_identity.len, presentity_impurecord->public_identity.s);
-        goto done;
-    }
-
-    ul.lock_subscription(subscription);
-    subscription->ref_count++;
-    LM_DBG("subscription ref count after add is now %d\n", subscription->ref_count);
-    ul.unlock_subscription(subscription);
 
     //now update the implicit set
     for (i = 0; i < subscription->service_profiles_cnt; i++) {
         for (j = 0; j < subscription->service_profiles[i].public_identities_cnt; j++) {
             pi = &(subscription->service_profiles[i].public_identities[j]);
 
-            if (memcmp(presentity_impurecord->public_identity.s, pi->public_identity.s, presentity_impurecord->public_identity.len) == 0) { //we don't need to update the explicit IMPU
-                LM_DBG("Ignoring explicit identity <%.*s>, updating later.....\n", presentity_impurecord->public_identity.len, presentity_impurecord->public_identity.s);
-                goto next_implicit_impu;
-            }
+            //            if ((presentity_aor->len == pi->public_identity.len) && memcmp(presentity_aor.s, pi->public_identity.s, presentity_aor->len) == 0) { //we don't need to update the explicit IMPU
+            //                LM_DBG("Ignoring explicit identity <%.*s>, updating later..... end of fn\n", presentity_aor.len, presentity_aor->s);
+            //                goto next_implicit_impu;
+            //            }
             ul.lock_udomain(_d, &pi->public_identity);
             if (ul.get_impurecord(_d, &pi->public_identity, &implicit_impurecord) != 0) {
                 LM_DBG("usrloc does not have impurecord for implicity IMPU, ignore\n");
                 goto next_implicit_impu;
             }
-            if (ul.get_ucontact(implicit_impurecord, &contact_uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist
+            if (ul.get_ucontact(&contact_uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist
                 LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_ONLY\n", contact_uri.len, contact_uri.s);
                 goto next_implicit_impu;
             } else {//contact exists
-                get_act_time();
-                if (VALID_CONTACT(ucontact, act_time)) {
+                if (ucontact->state != CONTACT_DELETED) {
                     if (contact_state == STATE_TERMINATED) {
                         //delete contact
                         LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
                         ul.lock_contact_slot(&contact_uri);
-                        if (ul.unlink_contact_from_impu(implicit_impurecord, ucontact, 1, 0 /*implicit dereg of contact from IMPU*/) != 0) {
-                            LM_ERR("Failed to delete ucontact <%.*s> from implicit IMPU\n", contact_uri.len, contact_uri.s);
-                            ul.unlock_contact_slot(&contact_uri);
-                            ul.release_ucontact(ucontact);
-                            goto next_implicit_impu; //TODO: don't need to use goto here...
+                        ucontact->state = CONTACT_DELETE_PENDING;
+                        if (implicit_impurecord->shead) {
+                            //send NOTIFY to all subscribers of this IMPU.
+                            notify_subscribers(implicit_impurecord);
                         }
                         ul.unlock_contact_slot(&contact_uri);
+                        //                        if (ul.unlink_contact_from_impu(implicit_impurecord, ucontact, 1, 0 /*implicit dereg of contact from IMPU*/) != 0) {
+                        //                            LM_ERR("Failed to delete ucontact <%.*s> from implicit IMPU\n", contact_uri.len, contact_uri.s);
+                        //                            ul.unlock_contact_slot(&contact_uri);
+                        //                            ul.release_ucontact(ucontact);
+                        //                            goto next_implicit_impu; //TODO: don't need to use goto here...
+                        //                        }
                     } else {//state is active
                         LM_DBG("This contact: <%.*s> is not in state terminated and is in usrloc, ignore\n", contact_uri.len, contact_uri.s);
                         ul.release_ucontact(ucontact);
@@ -620,42 +629,59 @@ next_implicit_impu:
         }
     }
 
-    ul.lock_subscription(subscription);
-    subscription->ref_count--;
-    LM_DBG("subscription ref count after sub is now %d\n", subscription->ref_count);
-    ul.unlock_subscription(subscription);
-
-    //	ul.lock_udomain(_d, &presentity_impurecord->public_identity);
-
-    if (ul.get_ucontact(presentity_impurecord, &contact_uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist
-        LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_ONLY\n", contact_uri.len, contact_uri.s);
-        return ret;
-    } else {//contact exists
-        get_act_time();
-        if (VALID_CONTACT(ucontact, act_time)) {
-            if (contact_state == STATE_TERMINATED) {
-                //delete contact
-                LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
-                ul.lock_contact_slot(&contact_uri);
-                if (ul.unlink_contact_from_impu(presentity_impurecord, ucontact, 1, 0 /*implicit dereg of contact from IMPU */) != 0) {
-                    LM_ERR("Failed to delete ucontact <%.*s>\n", contact_uri.len, contact_uri.s);
-                    ret = CSCF_RETURN_FALSE;
-                    ul.unlock_contact_slot(&contact_uri);
-                    ul.release_ucontact(ucontact);
-                    goto done;
-                }
-                ul.unlock_contact_slot(&contact_uri);
-            } else {//state is active
-                LM_DBG("This contact: <%.*s> is not in state terminated and is in usrloc, ignore\n", contact_uri.len, contact_uri.s);
-                ul.release_ucontact(ucontact);
-                goto done;
-            }
+    if (contact_state == STATE_TERMINATED) {
+        //at this point we can assume that all notifies were sent out to the subscribers of the IMPUs related to the explicit and implicit impus.
+        //we must now change the state of the contact to deleted so they can be removed from the IMPU in the timer process...
+        if (ul.get_ucontact(&contact_uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist
+            LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_ONLY\n", contact_uri.len, contact_uri.s);
+        } else {
+            ul.lock_contact_slot(&contact_uri);
+            ucontact->state = CONTACT_DELETED;
+            ul.unlock_contact_slot(&contact_uri);
+            ul.release_ucontact(ucontact);
         }
-        ul.release_ucontact(ucontact);
     }
 
-done:
-    ul.unlock_udomain(_d, &presentity_impurecord->public_identity);
+    //    ul.lock_subscription(subscription);
+    //    subscription->ref_count--;
+    //    LM_DBG("subscription ref count after sub is now %d\n", subscription->ref_count);
+    //    ul.unlock_subscription(subscription);
+
+    //	ul.lock_udomain(_d, &presentity_impurecord->public_identity);
+
+    //    if (ul.get_ucontact(&contact_uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist
+    //        LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_ONLY\n", contact_uri.len, contact_uri.s);
+    //        return ret;
+    //    } else {//contact exists
+    //        if (VALID_CONTACT(ucontact, act_time)) {
+    //            if (contact_state == STATE_TERMINATED) {
+    //                //delete contact
+    //                LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
+    ////                ul.lock_contact_slot(&contact_uri);
+    ////                if (ul.unlink_contact_from_impu(presentity_impurecord, ucontact, 1, 0 /*implicit dereg of contact from IMPU */) != 0) {
+    ////                    LM_ERR("Failed to delete ucontact <%.*s>\n", contact_uri.len, contact_uri.s);
+    ////                    ret = CSCF_RETURN_FALSE;
+    ////                    ul.unlock_contact_slot(&contact_uri);
+    ////                    ul.release_ucontact(ucontact);
+    ////                    goto done;
+    ////                }
+    ////                ul.unlock_contact_slot(&contact_uri);
+    //                ucontact->state = CONTACT_DELETE_PENDING;
+    //                if (implicit_impurecord->shead) {
+    //                    //send NOTIFY to all subscribers of this IMPU.
+    //                    notify_subscribers(implicit_impurecord);
+    //                }
+    //            } else {//state is active
+    //                LM_DBG("This contact: <%.*s> is not in state terminated and is in usrloc, ignore\n", contact_uri.len, contact_uri.s);
+    //                ul.release_ucontact(ucontact);
+    //                goto done;
+    //            }
+    //        }
+    //        ul.release_ucontact(ucontact);
+    //    }
+
+    //done:
+    //    ul.unlock_udomain(_d, &presentity_impurecord->public_identity);
     return ret;
 }
 
@@ -742,6 +768,8 @@ int process_publish_body(struct sip_msg* msg, str publish_body, udomain_t * doma
     char * expires_char, * cseq_char;
     int cseq = 0;
     impurecord_t* presentity_impurecord;
+    ims_subscription* subscription = 0;
+    int subscription_locked;
 
     doc = xmlParseMemory(publish_body.s, publish_body.len);
     if (doc == NULL) {
@@ -756,6 +784,7 @@ int process_publish_body(struct sip_msg* msg, str publish_body, udomain_t * doma
     }
     registrations = doc_root->children;
     while (registrations) {
+        subscription_locked = 0;
         /* Only process registration sub-items */
         if (xmlStrcasecmp(registrations->name, BAD_CAST "registration") != 0)
             goto next_registration;
@@ -771,13 +800,26 @@ int process_publish_body(struct sip_msg* msg, str publish_body, udomain_t * doma
         //TOD get IMPU record here
         ul.lock_udomain(domain, &aor);
         if (ul.get_impurecord(domain, &aor, &presentity_impurecord) != 0) {
-            LM_DBG("usrloc does not have imprecord for presentity being published too, ignore\n");
+            LM_DBG("usrloc does not have impurecord for presentity being published too, ignore\n");
             ul.unlock_udomain(domain, &aor);
             goto next_registration;
         }
+        //get the subscription which we will use later
+
+        subscription = presentity_impurecord->s;
+        if (!subscription) {
+            LM_DBG("No subscriber info associated with <%.*s>, so no implicit IMPUs to process\n", presentity_impurecord->public_identity.len, presentity_impurecord->public_identity.s);
+            goto next_registration;
+        }
+        ul.lock_subscription(subscription);
+        subscription->ref_count++;
+        LM_DBG("subscription ref count after add is now %d\n", subscription->ref_count);
+        ul.unlock_subscription(subscription);
+        subscription_locked = 1;
+
         ul.unlock_udomain(domain, &aor);
 
-        LM_DBG("Received impurecord for presentity being published on [%.*s]\n", presentity_impurecord->public_identity.len, presentity_impurecord->public_identity.s);
+        LM_DBG("Received impurecord for presentity being published on [%.*s]\n", aor.len, aor.s);
 
         if (reg_state == STATE_TERMINATED) {
             LM_DBG("This impurecord is in STATE_TERMINATED - TODO we should should delete all contacts");
@@ -871,7 +913,7 @@ int process_publish_body(struct sip_msg* msg, str publish_body, udomain_t * doma
                             contact_uri.len, contact_uri.s);
 
                     /* Add to Usrloc: */
-                    result = process_contact(presentity_impurecord, domain, expires, contact_uri, contact_state);
+                    result = process_contact(subscription, domain, expires, contact_uri, contact_state);
 
                     /* Process the result */
                     if (final_result != CSCF_RETURN_TRUE) final_result = result;
@@ -884,6 +926,12 @@ next_contact:
         }
 next_registration:
         registrations = registrations->next;
+    if (subscription_locked) {
+        ul.lock_subscription(subscription);
+        subscription->ref_count--;
+        LM_DBG("subscription ref count after sub is now %d\n", subscription->ref_count);
+        ul.unlock_subscription(subscription);
+    }
     }
 error:
     /* Free the XML-Document */
@@ -1184,7 +1232,7 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
         subscribe_reply(msg, 200, MSG_REG_SUBSCRIBE_OK, &expires, &scscf_name_str);
 
         //do reg event every time you get a subscribe
-        if (event_reg(domain, 0, 0, event_type, &presentity_uri, &watcher_contact) != 0) {
+        if (event_reg(domain, 0, event_type, &presentity_uri, &watcher_contact) != 0) {
             LM_ERR("failed adding notification for reg events\n");
             ret = CSCF_RETURN_ERROR;
             goto doneorerror;
@@ -1222,8 +1270,8 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
         LM_DBG("Sending 200 OK to subscribing user");
         subscribe_reply(msg, 200, MSG_REG_UNSUBSCRIBE_OK, &expires, &scscf_name_str);
     }
-    
-doneorerror:    
+
+doneorerror:
     //free memory
     if (presentity_uri.s) shm_free(presentity_uri.s); // shm_malloc in cscf_get_public_identity_from_requri or get_presentity_from_subscriber_dialog
     if (record_route.s) pkg_free(record_route.s);
@@ -1343,7 +1391,7 @@ static str subs_active = {"active;expires=", 15};
  * @param content - the body content
  * @param expires - the remaining subcription expiration time in seconds
  */
-void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_passed, str *presentity_uri, str *watcher_contact, str content, int event_type) {
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str content, int event_type) {
 
     reg_notification *n;
     reg_subscriber *s;
@@ -1362,7 +1410,7 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_p
 
     LM_DBG("Creating notification");
 
-    if (r_passed && c_passed && !presentity_uri && !watcher_contact) {
+    if (r_passed && !presentity_uri && !watcher_contact) {
         LM_DBG("r_passed and c_passed are valid and presentity uri and watcher_contact is 0 - this must be a ul callback no need to lock domain");
         r = r_passed;
 
@@ -1424,13 +1472,14 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_p
             }
         } else {
 
-            if (event_type == IMS_REGISTRAR_CONTACT_UNREGISTERED && !ue_unsubscribe_on_dereg &&
-                    (contact_port_ip_match(&c_passed->c, &s->watcher_contact) &&
-                    (r_passed->public_identity.len == s->presentity_uri.len) && (memcmp(s->presentity_uri.s, r_passed->public_identity.s, r_passed->public_identity.len) == 0))) {
-                //if this is UNREGISTER and the UEs do not unsubscribe to dereg and this is a UE subscribing to its own reg event
-                //then we do not send notifications
-                LM_DBG("This is a UNREGISTER event for a UE that subscribed to its own state that does not unsubscribe to dereg - therefore no notification");
-            } else {
+            //TODO: we must make this optimisation to not send NOTIFYs back to UE's *(they may have disappeared)
+//            if (event_type == IMS_REGISTRAR_CONTACT_UNREGISTERED && !ue_unsubscribe_on_dereg /*&&
+//                    (contact_port_ip_match(&c_passed->c, &s->watcher_contact) */
+//                    && (r_passed->public_identity.len == s->presentity_uri.len) && (memcmp(s->presentity_uri.s, r_passed->public_identity.s, r_passed->public_identity.len) == 0)) {
+//                //if this is UNREGISTER and the UEs do not unsubscribe to dereg and this is a UE subscribing to its own reg event
+//                //then we do not send notifications
+//                LM_DBG("This is a UNREGISTER event for a UE that subscribed to its own state that does not unsubscribe to dereg - therefore no notification");
+//            } else {
                 LM_DBG("about to make new notification!");
 
                 LM_DBG("we always increment the local cseq and version before we send a new notification\n");
@@ -1447,7 +1496,7 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_p
                 } else {
                     LM_DBG("Notification does not exist");
                 }
-            }
+//            }
         }
         s = s->next;
 
@@ -1527,6 +1576,77 @@ static str contact_e = {"\t\t</contact>\n", 13};
 static str uri_s = {"\t\t\t<uri>", 8};
 static str uri_e = {"</uri>\n", 7};
 
+static void process_xml_for_contact(str* buf, str* pad, ucontact_t* ptr) {
+    int expires;
+    param_t *param;
+
+    if (ptr->state == CONTACT_DELETED)
+        return; 
+    
+    expires = ptr->expires - act_time;
+    if (expires < 0 || (ptr->state == CONTACT_DELETE_PENDING) || (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY)) {
+        LM_WARN("Contact expires is negative - setting to 0\n");
+        expires = 0;
+    }
+    if (expires == 0) {
+        if (ptr->q != -1) {
+            float q = (float) ptr->q / 1000;
+            sprintf(pad->s, contact_s_q.s, ptr, r_terminated.len, r_terminated.s,
+                    r_expired.len, r_expired.s, expires, q);
+        } else {
+            sprintf(pad->s, contact_s_q.s, ptr, r_terminated.len, r_terminated.s,
+                    r_expired.len, r_expired.s, expires);
+        }
+    } else {
+        if (ptr->q != -1) {
+            float q = (float) ptr->q / 1000;
+            sprintf(pad->s, contact_s_q.s, ptr, r_active.len, r_active.s,
+                    r_registered.len, r_registered.s, expires,
+                    q);
+        } else {
+            sprintf(pad->s, contact_s_q.s, ptr, r_active.len, r_active.s,
+                    r_registered.len, r_registered.s, expires);
+        }
+    }
+
+    pad->len = strlen(pad->s);
+    STR_APPEND(*buf, *pad);
+    STR_APPEND(*buf, uri_s);
+
+    LM_DBG("Appending contact address: <%.*s>", ptr->c.len, ptr->c.s);
+
+    STR_APPEND(*buf, (ptr->c));
+    STR_APPEND(*buf, uri_e);
+
+    param = ptr->params;
+    while (param) {
+        if (supported_param(&param->name) != 0) {
+            param = param->next;
+            continue;
+        }
+
+        if (param->body.len > 0) {
+            LM_DBG("This contact has params name: [%.*s] body [%.*s]\n", param->name.len, param->name.s, param->body.len, param->body.s);
+            if (param->body.s[0] == '<' && param->body.s[param->body.len - 1] == '>') {
+                LM_DBG("This param body starts with '<' and ends with '>' we will clean these for the NOTIFY XML with &lt; and &gt;\n");
+                sprintf(pad->s, contact_s_params_with_body_fix.s, param->name.len, param->name.s, param->body.len - 2, param->body.s + 1);
+            } else {
+                sprintf(pad->s, contact_s_params_with_body.s, param->name.len, param->name.s, param->body.len, param->body.s);
+            }
+
+            pad->len = strlen(pad->s);
+            STR_APPEND(*buf, *pad);
+        } else {
+            LM_DBG("This contact has params name: [%.*s] \n", param->name.len, param->name.s);
+            sprintf(pad->s, contact_s_params_no_body.s, param->name.len, param->name.s);
+            pad->len = strlen(pad->s);
+            STR_APPEND(*buf, *pad);
+        }
+        param = param->next;
+    }
+    STR_APPEND(*buf, contact_e);
+}
+
 /**
  * Creates the full reginfo XML.
  * @param pv - the r_public to create for
@@ -1542,18 +1662,15 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *pri
     impurecord_t *r;
     int i, j, res;
     ucontact_t* ptr;
-    param_t *param;
 
     buf.s = bufc;
     buf.len = 0;
     pad.s = padc;
     pad.len = 0;
-
-    int domain_locked = 1;
+    get_act_time();
+//    int domain_locked = 1;
     int terminate_impu = 1;
 
-    int expires;
-
     LM_DBG("Getting reginfo_full");
 
     STR_APPEND(buf, xml_start);
@@ -1563,31 +1680,33 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *pri
 
     for (i = 0; i < num_impus; i++) {
         LM_DBG("Scrolling through public identities, current one <%.*s>", impu_list[i].len, impu_list[i].s);
-        if (primary_locked && strncasecmp(impu_list[i].s, primary_impu->s, impu_list[i].len) == 0) {
-            LM_DBG("Don't need to lock this impu [%.*s]  as its a ul callback so already locked\n", impu_list[i].len, impu_list[i].s);
-            domain_locked = 0;
-        } else {
-            LM_DBG("Need to lock this impu\n");
-            ul.lock_udomain(_t, &impu_list[i]);
-            domain_locked = 1;
-        }
-
+//        if (primary_locked && strncasecmp(impu_list[i].s, primary_impu->s, impu_list[i].len) == 0) {
+//            LM_DBG("Don't need to lock this impu [%.*s]  as its a ul callback so already locked\n", impu_list[i].len, impu_list[i].s);
+//            domain_locked = 0;
+//        } else {
+//            LM_DBG("Need to lock this impu\n");
+//            ul.lock_udomain(_t, &impu_list[i]);
+//            domain_locked = 1;
+//        }
+
+        ul.lock_udomain(_t, &impu_list[i]);
+        
         res = ul.get_impurecord(_t, &(impu_list[i]), &r);
         if (res != 0) {
             LM_WARN("impu disappeared, ignoring it\n");
-            if (domain_locked) {
+//            if (domain_locked) {
                 ul.unlock_udomain(_t, &impu_list[i]);
-            }
+//            }
             continue;
         }
-        domain_locked = 1;
+        //        domain_locked = 1;
 
         LM_DBG("Retrieved IMPU record");
 
         j = 0;
         terminate_impu = 1;
         while (j < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[j])) {
-            if (((ptr->expires - act_time) > 0)) {
+            if (VALID_CONTACT(ptr, act_time)) {
                 LM_DBG("IMPU <%.*s> has another active contact <%.*s> so will set its state to active\n",
                         r->public_identity.len, r->public_identity.s, ptr->c.len, ptr->c.s);
                 terminate_impu = 0;
@@ -1611,84 +1730,20 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *pri
 
         j = 0;
         LM_DBG("Scrolling through contact for this IMPU");
+//        if (contact && !domain_locked /* we're dealing with the primary impu most likely related to de-reg */) {
+//            LM_DBG("We're dealing with the primary IMPU here AND a contact was passed in - must have been an explicit dereg\n");
+//            process_xml_for_contact(&buf, &pad, contact); //we do this because in the unlink_contact_from_impu the contact has already gone so we pass it in as a param...
+//        }
         while (j < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[j])) {
-            if (ptr->q != -1) {
-                LM_DBG("q value not equal to -1");
-                float q = (float) ptr->q / 1000;
-                expires = ptr->expires - act_time;
-                if (expires < 0) {
-                    LM_WARN("Contact expires is negative - setting to 0\n");
-                    expires = 0;
-                }
-                if (expires == 0) {
-                    sprintf(pad.s, contact_s_q.s, ptr, r_terminated.len, r_terminated.s,
-                            r_expired.len, r_expired.s, expires,
-                            q);
-                } else {
-                    sprintf(pad.s, contact_s_q.s, ptr, r_active.len, r_active.s,
-                            r_registered.len, r_registered.s, expires,
-                            q);
-                }
-
-            } else {
-                LM_DBG("q value equal to -1");
-                expires = ptr->expires - act_time;
-                if (expires < 0) {
-                    LM_WARN("Contact expires is negative - setting to 0\n");
-                    expires = 0;
-                }
-                if (expires == 0) {
-                    sprintf(pad.s, contact_s_q.s, ptr, r_terminated.len, r_terminated.s,
-                            r_expired.len, r_expired.s, expires);
-                } else {
-                    sprintf(pad.s, contact_s_q.s, ptr, r_active.len, r_active.s,
-                            r_registered.len, r_registered.s, expires);
-                }
-            }
-            pad.len = strlen(pad.s);
-            STR_APPEND(buf, pad);
-            STR_APPEND(buf, uri_s);
-
-            LM_DBG("Appending contact address: <%.*s>", ptr->c.len, ptr->c.s);
-
-            STR_APPEND(buf, (ptr->c));
-            STR_APPEND(buf, uri_e);
-
-            param = ptr->params;
-            while (param) {
-                if (supported_param(&param->name) != 0) {
-                    param = param->next;
-                    continue;
-                }
-
-                if (param->body.len > 0) {
-                    LM_DBG("This contact has params name: [%.*s] body [%.*s]\n", param->name.len, param->name.s, param->body.len, param->body.s);
-                    if (param->body.s[0] == '<' && param->body.s[param->body.len - 1] == '>') {
-                        LM_DBG("This param body starts with '<' and ends with '>' we will clean these for the NOTIFY XML with &lt; and &gt;\n");
-                        sprintf(pad.s, contact_s_params_with_body_fix.s, param->name.len, param->name.s, param->body.len - 2, param->body.s + 1);
-                    } else {
-                        sprintf(pad.s, contact_s_params_with_body.s, param->name.len, param->name.s, param->body.len, param->body.s);
-                    }
-
-                    pad.len = strlen(pad.s);
-                    STR_APPEND(buf, pad);
-                } else {
-                    LM_DBG("This contact has params name: [%.*s] \n", param->name.len, param->name.s);
-                    sprintf(pad.s, contact_s_params_no_body.s, param->name.len, param->name.s);
-                    pad.len = strlen(pad.s);
-                    STR_APPEND(buf, pad);
-                }
-                param = param->next;
-            }
-            STR_APPEND(buf, contact_e);
+            process_xml_for_contact(&buf, &pad, ptr);
             j++;
         }
 
         STR_APPEND(buf, registration_e);
 
-        if (domain_locked) {
+//        if (domain_locked) {
             ul.unlock_udomain(_t, &impu_list[i]);
-        }
+//        }
     }
 
     STR_APPEND(buf, r_reginfo_e);

+ 4 - 2
modules/ims_registrar_scscf/registrar_notify.h

@@ -123,14 +123,14 @@ int publish_reg(struct sip_msg *msg, char *str1, char *str2);
 
 int subscribe_reply(struct sip_msg *msg, int code, char *text, int *expires, str *contact);
 
-int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int event_type, str *presentity_uri, str *watcher_contact);
+int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact);
 
 
 str generate_reginfo_full(udomain_t* _t, str* impu_list, int new_subscription, str *primary_impu, int primary_locked);
 
 str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type);
 
-void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_passed, str *presentity_uri, str *watcher_contact, str content, int event_type);
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str content, int event_type);
 
 void notification_event_process();
 
@@ -152,4 +152,6 @@ void notify_destroy();
 int aor_to_contact(str* aor, str* contact);
 int contact_port_ip_match(str *c1, str *c2);
 
+int notify_subscribers(impurecord_t* impurecord);
+
 #endif //S_CSCF_REGISTRAR_NOTIFY_H_

+ 11 - 2
modules/ims_registrar_scscf/reply.c

@@ -65,6 +65,7 @@
 #define CONTACT_SEP_LEN (sizeof(CONTACT_SEP) - 1)
 
 extern str scscf_serviceroute_uri_str;
+extern int contact_expires_buffer_percentage;
 
 extern struct tm_binds tmb;
 
@@ -421,7 +422,7 @@ int build_expired_contact(contact_t* chi, contact_for_header_t** contact_header)
 
 int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header) {
     char *p, *cp;
-    int fl, len;
+    int fl, len, expires, expires_orig;
     ucontact_t* c;
     param_t* tmp;
     *contact_header = 0;
@@ -469,7 +470,15 @@ int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header)
 
                 memcpy(p, EXPIRES_PARAM, EXPIRES_PARAM_LEN);
                 p += EXPIRES_PARAM_LEN;
-                cp = int2str((int) (c->expires - act_time), &len);
+                
+                /* the expires we put in the contact header is decremented to give the UE some grace before we expires them */
+                expires = expires_orig = (int)(c->expires - act_time);
+                expires = expires - (contact_expires_buffer_percentage*expires/100);
+                if (expires <= 0) {
+                    LM_WARN("expires after buffer change was <= 0, not adding buffer space\n");
+                    expires = expires_orig;
+                }
+                cp = int2str(expires, &len);
                 memcpy(p, cp, len);
                 p += len;
     

+ 125 - 85
modules/ims_registrar_scscf/save.c

@@ -137,9 +137,9 @@ static inline int calc_contact_expires(contact_t *c, unsigned int expires_hdr, i
         r = default_registrar_cfg.em_min_expires;
 
 end:
-	    
+
     r = randomize_expires(r, default_registrar_cfg.default_expires_range);
-	    
+
     LM_DBG("Calculated expires for contact is %d\n", r);
     return time(NULL) + r;
 }
@@ -533,7 +533,7 @@ static inline int update_contacts_helper(struct sip_msg* msg, impurecord_t* impu
     qvalue_t qvalue;
     int sos = 0, expires;
     struct ucontact* ucontact;
-    int result;
+    int result, sl;
 
     LM_DBG("updating the contacts for IMPU <%.*s>\n", impu_rec->public_identity.len, impu_rec->public_identity.s);
 
@@ -575,9 +575,8 @@ static inline int update_contacts_helper(struct sip_msg* msg, impurecord_t* impu
                         LM_DBG("adding/updating contact based on prior existence\n");
                         //stick the contacts into usrloc
                         //ul.lock_contact_slot(&chi->uri);
-                        result = ul.get_ucontact(impu_rec, &chi->uri, ci->callid,
+                        result = ul.get_ucontact(&chi->uri, ci->callid,
                                 ci->path, ci->cseq, &ucontact);
-
                         if (result != 0) { //get_contact returns with lock
                             LM_DBG("inserting new contact\n");
                             if (ul.insert_ucontact(impu_rec, &chi->uri, ci,
@@ -587,17 +586,23 @@ static inline int update_contacts_helper(struct sip_msg* msg, impurecord_t* impu
                                 goto error;
                             }
                         } else {
-                            LM_DBG("Contact already exists - updating\n");
+                            LM_DBG("Contact already exists - updating - it's currently in state [%d]\n", ucontact->state);
+                            sl = ucontact->sl;
+                            ul.lock_contact_slot_i(sl);
+                            if (ucontact->state != CONTACT_VALID) {
+                                LM_WARN("contact is not in state valid - this is a race between dereg and reg/re-reg");
+                                ucontact->state = CONTACT_VALID; //TODO this should prob move into the contact info structure - ie pass state into update
+                            }
                             if (ul.update_ucontact(impu_rec, ucontact, ci) != 0) {
                                 LM_ERR("Error updating contact <%.*s>\n", chi->uri.len, chi->uri.s);
+                                ul.unlock_contact_slot_i(sl);
                                 ul.release_ucontact(ucontact);
                                 //				ul.unlock_contact_slot(&chi->uri);
                                 goto error;
                             }
+                            ul.unlock_contact_slot_i(sl);
                             ul.release_ucontact(ucontact);
                         }
-
-
                         //			ul.unlock_contact_slot(&chi->uri);
                     }
                 }
@@ -612,68 +617,66 @@ error:
 }
 
 /*NB remember to lock udomain prior to calling this*/
-static inline int unregister_contact(udomain_t* _d, str* public_identity, impurecord_t* _impu_rec, contact_t* chi) {
-    impurecord_t* impu_rec;
+static inline int unregister_contact(contact_t* chi, contact_state_t state) {
     struct ucontact* ucontact;
     str callid = {0, 0};
     str path = {0, 0};
 
-    reg_subscriber *s;
-
-    if (_impu_rec) {
-        LM_DBG("already have impurecord....\n");
-        impu_rec = _impu_rec;
-    } else {
-        if (ul.get_impurecord(_d, public_identity, &impu_rec) != 0) {
-            LM_ERR("Error, no public identity exists for <%.*s>\n", public_identity->len, public_identity->s);
-            goto error;
-        }
-    }
-
 
+    //    if (_impu_rec) {
+    //        LM_DBG("already have impurecord....\n");
+    //        impu_rec = _impu_rec;
+    //    } else {
+    //        if (ul.get_impurecord(_d, public_identity, &impu_rec) != 0) {
+    //            LM_ERR("Error, no public identity exists for <%.*s>\n", public_identity->len, public_identity->s);
+    //            goto error;
+    //        }
+    //    }
 
-    if (ul.get_ucontact(impu_rec, &chi->uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) {
+    if (ul.get_ucontact(&chi->uri, &callid, &path, 0/*cseq*/, &ucontact) != 0) {
         LM_ERR("Can't unregister contact that does not exist <%.*s>\n", chi->uri.len, chi->uri.s);
         //        ul.unlock_udomain(_d, public_identity);
         goto error;
     }
 
     get_act_time();
-    if (!VALID_CONTACT(ucontact, act_time)) {
-        LM_DBG("Contact is not valid (expired).... ignoring\n");
+    if (ucontact->state == CONTACT_DELETED) {
+        LM_DBG("Contact is not valid (expired/deleted).... ignoring\n");
         ul.release_ucontact(ucontact);
-        //        ul.unlock_udomain(_d, public_identity);
-        goto error;
+        return 0;
     }
 
     //Richard added this  - fix to remove subscribes that have presentity and watcher uri same as a contact aor that is being removed
     //When UEs explicitly dereg - they don't unsubscribe, so we remove subscriptions for them
     //only do this if ue_unsubscribe_on_dereg is set to 0
-    if (!ue_unsubscribe_on_dereg) {
-        s = impu_rec->shead;
-        LM_DBG("Checking if there is a subscription to this IMPU that has same watcher contact as this contact");
-        while (s) {
-
-            LM_DBG("Subscription for this impurecord: watcher uri [%.*s] presentity uri [%.*s] watcher contact [%.*s] ", s->watcher_uri.len, s->watcher_uri.s,
-                    s->presentity_uri.len, s->presentity_uri.s, s->watcher_contact.len, s->watcher_contact.s);
-            LM_DBG("Contact to be removed [%.*s] ", ucontact->c.len, ucontact->c.s);
-            if (contact_port_ip_match(&s->watcher_contact, &ucontact->c)) {
-                //if ((s->watcher_contact.len == ucontact->c.len) && (strncasecmp(s->watcher_contact.s, ucontact->c.s, ucontact->c.len) == 0)) {
-                LM_DBG("This contact has a subscription to its own status - so going to delete the subscription");
-                ul.external_delete_subscriber(s, _d, 0 /*domain is locked*/);
-            }
-            s = s->next;
-        }
-    }
+    //    if (!ue_unsubscribe_on_dereg) {
+    //        s = impu_rec->shead;
+    //        LM_DBG("Checking if there is a subscription to this IMPU that has same watcher contact as this contact");
+    //        while (s) {
+    //
+    //            LM_DBG("Subscription for this impurecord: watcher uri [%.*s] presentity uri [%.*s] watcher contact [%.*s] ", s->watcher_uri.len, s->watcher_uri.s,
+    //                    s->presentity_uri.len, s->presentity_uri.s, s->watcher_contact.len, s->watcher_contact.s);
+    //            LM_DBG("Contact to be removed [%.*s] ", ucontact->c.len, ucontact->c.s);
+    //            if (contact_port_ip_match(&s->watcher_contact, &ucontact->c)) {
+    //                //if ((s->watcher_contact.len == ucontact->c.len) && (strncasecmp(s->watcher_contact.s, ucontact->c.s, ucontact->c.len) == 0)) {
+    //                LM_DBG("This contact has a subscription to its own status - so going to delete the subscription");
+    //                ul.external_delete_subscriber(s, _d, 0 /*domain is locked*/);
+    //            }
+    //            s = s->next;
+    //        }
+    //    }
 
     //    if (ul.delete_ucontact(impu_rec, ucontact) != 0) {
     ul.lock_contact_slot_i(ucontact->sl);
-    if (ul.unlink_contact_from_impu(impu_rec, ucontact, 1, 1/*explicit dereg of contact*/) != 0) {
-        LM_ERR("Failed to delete ucontact <%.*s>\n", chi->uri.len, chi->uri.s);
-    }
+    ucontact->state = state;
+    //    notify_subscribers(impu_rec);
+    //    ucontact->state = CONTACT_DELETED;
+    //    if (ul.unlink_contact_from_impu(impu_rec, ucontact, 1, 1/*explicit dereg of contact*/) != 0) {
+    //        LM_ERR("Failed to delete ucontact <%.*s>\n", chi->uri.len, chi->uri.s);
+    //    }
     ul.unlock_contact_slot_i(ucontact->sl);
     ul.release_ucontact(ucontact);
-    LM_DBG("Contact unlinked successfully <%.*s>\n", chi->uri.len, chi->uri.s);
+    //    LM_DBG("Contact unlinked successfully <%.*s>\n", chi->uri.len, chi->uri.s);
     //    ul.unlock_udomain(_d, public_identity);
     return 0;
 
@@ -681,6 +684,24 @@ error:
     return -1;
 }
 
+/**
+ * Get the number of valid contacts for an impu. Ie contacts not expired and not in deleted or delete_pending state
+ * @param impu
+ * @return 
+ */
+int get_number_of_valid_contacts(impurecord_t* impu) {
+    int i;
+    int ret = 0;
+    get_act_time();
+    for (i = 0; i < impu->num_contacts; i++) {
+        if (VALID_CONTACT(impu->newcontacts[i], act_time)) {
+            ret++;
+        }
+    }
+
+    return ret;
+}
+
 /**
  * 
  * @param msg
@@ -713,7 +734,6 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
     int first_unbarred_impu = 1; //this is used to flag the IMPU as anchor for implicit set
     int is_primary_impu = 0;
     int ret = 1;
-
     if (msg) {
         expires_hdr = cscf_get_expires_hdr(msg, 0); //get the expires from the main body of the sip message (global)
     }
@@ -762,6 +782,7 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
             }
             //now build the contact buffer to be include in the reply message and unlock
             build_contact(impu_rec, contact_header);
+            notify_subscribers(impu_rec);
             ul.unlock_udomain(_d, public_identity);
             break;
         case AVP_IMS_SAR_RE_REGISTRATION:
@@ -838,17 +859,11 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
             if (ul.update_impurecord(_d, public_identity, 0, reg_state, -1 /*do not change send sar on delete */, 0 /*this is explicit so barring must be 0*/, 0, s, ccf1, ccf2, ecf1, ecf2, &impu_rec) != 0) {
                 LM_ERR("Unable to update explicit impurecord for <%.*s>\n", public_identity->len, public_identity->s);
             }
+            notify_subscribers(impu_rec);
             break;
         case AVP_IMS_SAR_USER_DEREGISTRATION:
             /*TODO: if its not a star lets find all the contact records and remove them*/
-            ul.lock_udomain(_d, public_identity);
-
-            if (ul.get_impurecord(_d, public_identity, &impu_rec) != 0) {
-                LM_ERR("Error retrieving impu record\n");
-                ul.unlock_udomain(_d, public_identity);
-                goto error;
-            }
-
+            //first we update the state of the contact/s
             for (h = msg->contact; h; h = h->next) {
                 if (h->type == HDR_CONTACT_T && h->parsed) {
                     for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
@@ -862,7 +877,7 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                             goto error;
                         }
                         calc_contact_expires(chi, expires_hdr, sos);
-                        if (unregister_contact(_d, public_identity, impu_rec, chi) != 0) {
+                        if (unregister_contact(chi, CONTACT_DELETE_PENDING) != 0) {
                             LM_ERR("Unable to remove contact <%.*s\n", chi->uri.len, chi->uri.s);
 
                         }
@@ -871,8 +886,16 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                     }
                 }
             }
- 
-            if (impu_rec->num_contacts >= 0 && impu_rec->newcontacts[0]) {
+
+            //now, we get the subscription
+            ul.lock_udomain(_d, public_identity);
+            if (ul.get_impurecord(_d, public_identity, &impu_rec) != 0) {
+                LM_ERR("Error retrieving impu record on explicit de-reg nothing we can do from here on... aborting..\n");
+                ul.unlock_udomain(_d, public_identity);
+                goto error;
+            }
+            int num_contacts = get_number_of_valid_contacts(impu_rec);
+            if (num_contacts > 0) {
                 LM_DBG("contacts still available\n");
                 //TODO: add all other remaining contacts to reply message (contacts still registered for this IMPU)
                 ret = 1;
@@ -880,8 +903,6 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                 LM_DBG("no more contacts available\n");
                 ret = 2;
             }
-
-            //before we release IMPU record - lets save the subscription for implicit dereg
             ims_subscription* subscription = impu_rec->s;
 
             if (!subscription) {
@@ -890,17 +911,18 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                 ul.lock_subscription(subscription);
                 subscription->ref_count++; //this is so we can de-reg the implicit set just now without holding the lock on the current IMPU
                 ul.unlock_subscription(subscription);
+            }
 
-                ul.unlock_udomain(_d, public_identity);
-                //TODO: this needs a clean......
-                //lock(subscription->lock);
+            ul.unlock_udomain(_d, public_identity);
+
+            if (subscription) {
                 for (i = 0; i < subscription->service_profiles_cnt; i++) {
                     for (j = 0; j < subscription->service_profiles[i].public_identities_cnt; j++) {
                         pi = &(subscription->service_profiles[i].public_identities[j]);
-                        if (memcmp(public_identity->s, pi->public_identity.s, public_identity->len) == 0) { //we don't need to update the explicit IMPU
-                            LM_DBG("Ignoring explicit identity <%.*s>, already de-reg/updated\n", public_identity->len, public_identity->s);
-                            continue;
-                        }
+                        //                        if (memcmp(public_identity->s, pi->public_identity.s, public_identity->len) == 0) { //we don't need to update the explicit IMPU
+                        //                            LM_DBG("Ignoring explicit identity <%.*s>, already de-reg/updated\n", public_identity->len, public_identity->s);
+                        //                            continue;
+                        //                        }
                         ul.lock_udomain(_d, &pi->public_identity);
                         if (ul.get_impurecord(_d, &pi->public_identity, &tmp_impu_rec) != 0) {
                             LM_ERR("Can't find IMPU for implicit de-registration update....continuing\n");
@@ -908,6 +930,24 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                             continue;
                         }
                         LM_DBG("Implicit deregistration of IMPU <%.*s>\n", pi->public_identity.len, pi->public_identity.s);
+                        //TODO_LATEST: need to add back the following functionality
+                        //                        if (!ue_unsubscribe_on_dereg) {
+                        //                            subscriber = tmp_impu_rec->shead;
+                        //                            LM_DBG("Checking if there is a subscription to this IMPU that has same watcher contact as this contact");
+                        //                            while (s) {
+                        //
+                        //                                LM_DBG("Subscription for this impurecord: watcher uri [%.*s] presentity uri [%.*s] watcher contact [%.*s] ", subscriber->watcher_uri.len, subscriber->watcher_uri.s,
+                        //                                        subscriber->presentity_uri.len, subscriber->presentity_uri.s, subscriber->watcher_contact.len, subscriber->watcher_contact.s);
+                        //                                LM_DBG("Contact to be removed [%.*s] ", ucontact->c.len, ucontact->c.s);
+                        //                                if (contact_port_ip_match(&subscriber->watcher_contact, &ucontact->c)) {
+                        //                                    //if ((s->watcher_contact.len == ucontact->c.len) && (strncasecmp(s->watcher_contact.s, ucontact->c.s, ucontact->c.len) == 0)) {
+                        //                                    LM_DBG("This contact has a subscription to its own status - so going to delete the subscription");
+                        //                                    ul.external_delete_subscriber(subscriber, _d, 0 /*domain is locked*/);
+                        //                                }
+                        //                                s = s->next;
+                        //                            }
+                        //                        }
+                        notify_subscribers(tmp_impu_rec);
                         for (h = msg->contact; h; h = h->next) {
                             if (h->type == HDR_CONTACT_T && h->parsed) {
                                 for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
@@ -924,16 +964,16 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                                         goto error;
                                     }
                                     calc_contact_expires(chi, expires_hdr, sos);
-                                    if (unregister_contact(_d, 0, tmp_impu_rec, chi) != 0) {
-                                        LM_ERR("Unable to remove contact <%.*s\n", chi->uri.len, chi->uri.s);
+                                    if (unregister_contact(chi, CONTACT_DELETED) != 0) {
+                                        LM_ERR("Unable to remove contact <%.*s>\n", chi->uri.len, chi->uri.s);
 
                                     }
                                 }
                             }
                         }
                         /*now lets see if we still have any contacts left to decide on return value*/
-
-                        if (tmp_impu_rec->num_contacts && tmp_impu_rec->newcontacts[0])
+                        int num_valid_contacts = get_number_of_valid_contacts(tmp_impu_rec);
+                        if (num_valid_contacts)
                             LM_DBG("contacts still available after implicit dereg for IMPU: <%.*s>\n", pi->public_identity.len, pi->public_identity.s);
                         else {
                             LM_DBG("no contacts left after implicit dereg for IMPU: <%.*s>\n", pi->public_identity.len, pi->public_identity.s);
@@ -1007,12 +1047,12 @@ int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction, char* ro
     cfg_action_t* cfg_action;
 
     udomain_t* _d = (udomain_t*) str1;
-    
+
     if (fixup_get_svalue(_m, (gparam_t*) route, &route_name) != 0) {
         LM_ERR("no async route block for assign_server_unreg\n");
         return -1;
     }
-    
+
     LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
     int ri = route_get(&main_rt, route_name.s);
     if (ri < 0) {
@@ -1024,7 +1064,7 @@ int assign_server_unreg(struct sip_msg* _m, char* str1, str* direction, char* ro
         LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
         return -1;
     }
-    
+
     LM_DBG("Assigning unregistered user for direction [%.*s]\n", direction->len, direction->s);
 
     enum cscf_dialog_direction dir = cscf_get_dialog_direction(direction->s);
@@ -1137,7 +1177,7 @@ int save(struct sip_msg* msg, char* str1, char *route) {
     str public_identity, private_identity, realm;
     int sar_assignment_type = AVP_IMS_SAR_NO_ASSIGNMENT;
     str route_name;
-    
+
     udomain_t* _d = (udomain_t*) str1;
 
     rerrno = R_FINE;
@@ -1154,7 +1194,7 @@ int save(struct sip_msg* msg, char* str1, char *route) {
         LM_ERR("no async route block for assign_server_unreg\n");
         return -1;
     }
-    
+
     LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
     int ri = route_get(&main_rt, route_name.s);
     if (ri < 0) {
@@ -1245,7 +1285,7 @@ int save(struct sip_msg* msg, char* str1, char *route) {
                 goto error;
             } else if (res == 2) {
                 //send sar
-                LM_DBG("no contacts left after de-registration, doing SAR\n");
+                LM_DBG("no contacts left after explicit de-registration, doing SAR\n");
             } else { //res=1
                 //still contacts left so return success
                 LM_DBG("contacts still available after deregister.... not doing SAR\n");
@@ -1256,16 +1296,16 @@ int save(struct sip_msg* msg, char* str1, char *route) {
             }
         }
     }
-    
+
     if (!user_data_always) {
-	if (require_user_data)
-	    data_available = AVP_IMS_SAR_USER_DATA_NOT_AVAILABLE;
-	else
-	    data_available = AVP_IMS_SAR_USER_DATA_ALREADY_AVAILABLE;
+        if (require_user_data)
+            data_available = AVP_IMS_SAR_USER_DATA_NOT_AVAILABLE;
+        else
+            data_available = AVP_IMS_SAR_USER_DATA_ALREADY_AVAILABLE;
     } else {
-	data_available = AVP_IMS_SAR_USER_DATA_NOT_AVAILABLE;
+        data_available = AVP_IMS_SAR_USER_DATA_NOT_AVAILABLE;
     }
-    
+
     //before we send lets suspend the transaction
     t = tmb.t_gett();
     if (t == NULL || t == T_UNDEFINED) {

+ 2 - 16
modules/ims_registrar_scscf/usrloc_cb.c

@@ -91,23 +91,9 @@ void ul_contact_changed(impurecord_t* r, ucontact_t* c, int type, void* param) {
         LM_DBG("There are no subscriptions for this IMPU therefore breaking out now as nothing to do");
         return;
     }
-    
+//    
     if (type == UL_IMPU_DELETE_CONTACT) {
         LM_DBG("Received notification of UL CONTACT DELETE");
-        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0);
-    } else if (type == UL_IMPU_DELETE_CONTACT_IMPLICIT) {
-        LM_DBG("Received notification of UL CONTACT_DELETE_IMPLICIT");
-        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_UNREGISTERED_IMPLICIT, 0, 0);
-    } else if (type == UL_IMPU_EXPIRE_CONTACT) {
-        LM_DBG("Received notification of UL CONTACT EXPIRE");
-        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_EXPIRED, 0, 0);
-    } else if (type == UL_IMPU_UPDATE_CONTACT) {
-        LM_DBG("Received notification of UL CONTACT UPDATE");
-        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_REFRESHED, 0, 0);
-    } else if (type == UL_IMPU_NEW_CONTACT) {
-        LM_DBG("Received notification of UL IMPU CONTACT INSERT");
-        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0);
-    } else {
-        LM_DBG("This type of callback not supported here");
+        event_reg(0, r, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0);
     }
 }

+ 76 - 51
modules/ims_usrloc_pcscf/pcontact.c

@@ -61,6 +61,8 @@
 extern int db_mode;
 extern int hashing_type;
 
+extern int expires_grace;
+
 /*! retransmission detection interval in seconds */
 int cseq_delay = 20;
 
@@ -113,13 +115,14 @@ void free_ppublic(ppublic_t* _p)
 
 int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c)
 {
-	int i;
+	int i, has_rinstance=0;
 	ppublic_t* ppublic_ptr;
-	int is_default = 1;
+	int is_default = 1, params_len;
 	struct sip_uri sip_uri;
-
-
-	*_c = (pcontact_t*)shm_malloc(sizeof(pcontact_t));
+        char* p, *params, *sep;
+        str rinstance = {0,0};
+        
+	*_c = (pcontact_t*)shm_malloc(sizeof(pcontact_t) + _contact->len + _ci->received_host.len + _ci->via_host.len);
 	if (*_c == 0) {
 		LM_ERR("no more shared memory\n");
 		return -1;
@@ -130,15 +133,13 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 			_contact->len, _contact->s,
 			_ci->num_public_ids,
 			reg_state_to_string(_ci->reg_state));
+        
+        
 
-	(*_c)->aor.s = (char*) shm_malloc(_contact->len);
-	if ((*_c)->aor.s == 0) {
-		LM_ERR("no more shared memory\n");
-		shm_free(*_c);
-		*_c = 0;
-		return -2;
-	}
-	memcpy((*_c)->aor.s, _contact->s, _contact->len);
+        p = (char*)((struct pcontact*)(*_c) + 1);
+        (*_c)->aor.s = p;
+	memcpy(p, _contact->s, _contact->len);
+        p += _contact->len;
 	(*_c)->aor.len = _contact->len;
 	(*_c)->domain = (str*)_d;
 
@@ -149,6 +150,36 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 		*_c = 0;
 		return -2;
 	}
+        
+        /* is there an rinstance param */
+        LM_DBG("checking for rinstance");
+        /*check for alias - NAT */
+        params = sip_uri.sip_params.s;
+        params_len = sip_uri.sip_params.len;
+        while (params_len >= RINSTANCE_LEN) {
+            if (strncmp(params, RINSTANCE, RINSTANCE_LEN) == 0) {
+                has_rinstance = 1;
+                break;
+            }
+            sep = memchr(params, 59 /* ; */, params_len);
+            if (sep == NULL) {
+                LM_DBG("no rinstance param\n");
+                break;
+            } else {
+                params_len = params_len - (sep - params + 1);
+                params = sep + 1;
+            }
+        }
+        if (has_rinstance) {
+            rinstance.s = params + RINSTANCE_LEN;
+            rinstance.len = params_len - RINSTANCE_LEN;
+            sep = (char*)memchr(rinstance.s, 59 /* ; */, rinstance.len);
+            if (sep != NULL){
+                rinstance.len = (sep-rinstance.s);
+            }
+        }
+        (*_c)->rinstance.s = rinstance.s;
+        (*_c)->rinstance.len = rinstance.len;
 	(*_c)->contact_host.s = sip_uri.host.s;
 	(*_c)->contact_host.len = sip_uri.host.len;
 	(*_c)->contact_port = sip_uri.port_no;
@@ -160,36 +191,24 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 
 	// Add received Info:
 	if (_ci->received_host.len > 0 && _ci->received_host.s) {
-		(*_c)->received_host.s = (char*) shm_malloc(_ci->received_host.len);
-		if ((*_c)->received_host.s == 0) {
-			LM_ERR("no more share memory\n");
-			shm_free((*_c)->aor.s);
-			shm_free(*_c);
-			*_c = 0;
-			return -2;
-		}
-		memcpy((*_c)->received_host.s, _ci->received_host.s, _ci->received_host.len);
+        (*_c)->received_host.s = p;
+		memcpy(p, _ci->received_host.s, _ci->received_host.len);
+                p += _ci->received_host.len;
 		(*_c)->received_host.len = _ci->received_host.len;
 		(*_c)->received_port = _ci->received_port;
 		(*_c)->received_proto = _ci->received_proto;
 	}
-
-	if (hashing_type==0) {
-		(*_c)->aorhash = core_hash(_contact, 0, 0);
-	} else if (hashing_type==1) {
-		if ((*_c)->received_host.len > 0 && memcmp((*_c)->contact_host.s, (*_c)->received_host.s, (*_c)->contact_host.len) != 0) {
-		    LM_DBG("Looks like this contact is natted - contact URI: [%.*s] but came from [%.*s]\n", (*_c)->contact_host.len, 
-		    (*_c)->contact_host.s, (*_c)->received_host.len, (*_c)->received_host.s);
-		    (*_c)->aorhash = core_hash(&(*_c)->received_host, 0, 0);
-		} else 
-		    (*_c)->aorhash = core_hash(&(*_c)->contact_host, 0, 0);
-	} else {
-		if ((*_c)->received_host.len > 0) {
-			(*_c)->aorhash = core_hash(&(*_c)->received_host, 0, 0);	
-		} else {
-			(*_c)->aorhash = core_hash(&(*_c)->contact_host, 0, 0);
-		}
-	}
+        
+        if (_ci->via_host.len > 0 && _ci->via_host.s) {
+            (*_c)->via_host.s = p;
+            memcpy(p, _ci->via_host.s, _ci->via_host.len);
+            p += _ci->via_host.len;
+            (*_c)->via_host.len = _ci->via_host.len;
+            (*_c)->via_port = _ci->via_port;
+            (*_c)->via_proto = _ci->via_prot;
+        }
+        
+        (*_c)->aorhash = get_aor_hash(_d, &_ci->via_host, _ci->via_port, _ci->via_prot);
 
 	//setup public ids
 	for (i=0; i<_ci->num_public_ids; i++) {
@@ -213,6 +232,12 @@ int new_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, s
 			(*_c)->num_service_routes = _ci->num_service_routes;
 		}
 	}
+        
+        LM_DBG("New contact host:port [%.*s:%d]\n", (*_c)->contact_host.len, (*_c)->contact_host.s, (*_c)->contact_port);
+        LM_DBG("New contact via host:port:proto: [%.*s:%d:%d]\n", (*_c)->via_host.len, (*_c)->via_host.s, (*_c)->via_port, (*_c)->via_proto);
+        LM_DBG("New contact received host:port:proto: [%.*s:%d:%d]\n", (*_c)->received_host.len, (*_c)->received_host.s, (*_c)->received_port, (*_c)->received_proto);
+        LM_DBG("New contact aorhash [%u]\n", (*_c)->aorhash);
+        
 	return 0;
 
 out_of_memory:
@@ -250,15 +275,6 @@ void free_pcontact(pcontact_t* _c) {
 			_c->num_service_routes = 0;
 		}
 	}
-	//free URI
-	if (_c->aor.s) {
-		shm_free(_c->aor.s);
-	}
-
-	//free received host
-	if (_c->received_host.s) {
-		shm_free(_c->received_host.s);
-	}
 
 	if (_c->rx_session_id.len > 0 && _c->rx_session_id.s)
 		shm_free(_c->rx_session_id.s);
@@ -272,17 +288,26 @@ static inline void nodb_timer(pcontact_t* _c)
 			"Expires: %d, "
 			"Expires in: %d seconds, "
 			"Received: %.*s:%d, "
-			"Proto: %d\n",
+                        "Path: %.*s, "
+			"Proto: %d, "
+                        "Hash: %u, " 
+                        "Slot: %u\n",
 			_c->aor.len, _c->aor.s,
 			reg_state_to_string(_c->reg_state),
 			(int)_c->expires,
 			(int)(_c->expires - time(NULL)),
 			_c->received_host.len, _c->received_host.s,
 			_c->received_port,
-			_c->received_proto);
+                        _c->path.len, _c->path.s,
+			_c->received_proto,
+                        _c->aorhash,
+                        _c->sl);
 
 	get_act_time();
-	if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter
+        
+        
+        if ((_c->expires - act_time) + expires_grace <= 0) {//we've allowed some grace time TODO: add as parameter
+        //if ((_c->expires - act_time) <= -10) {//we've allowed some grace time TODO: add as parameter
 		LM_DBG("pcscf contact <%.*s> has expired and will be removed\n", _c->aor.len, _c->aor.s);
 		if (exists_ulcb_type(PCSCF_CONTACT_EXPIRE)) {
 			run_ul_callbacks(PCSCF_CONTACT_EXPIRE, _c);

+ 2 - 2
modules/ims_usrloc_pcscf/pcontact.h

@@ -70,8 +70,8 @@ void timer_pcontact(pcontact_t* _r);
 int delete_ppublic(pcontact_t* _r/*, struct ucontact* _c*/);
 int get_ppublic(pcontact_t* _r);
 int aor_to_contact(str* aor, str* contact);
-unsigned int get_hash_slot(udomain_t* _d, str* _aor, str* received_host, int received_port);
-unsigned int get_aor_hash(udomain_t* _d, str* _aor, str* received_host, int received_port);
+unsigned int get_hash_slot(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto);
+unsigned int get_aor_hash(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto);
 
 
 #endif

+ 241 - 206
modules/ims_usrloc_pcscf/udomain.c

@@ -60,8 +60,10 @@
 #include "../../parser/parse_uri.h"
 
 #include "../../lib/ims/useful_defs.h"
+#include "../../modules/presence/presence.h"
 
 extern int db_mode;
+extern int db_mode_ext;
 extern unsigned int hashing_type;
 extern int lookup_check_received;
 extern int match_contact_host_port;
@@ -230,6 +232,7 @@ int mem_insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info*
 
 	sl = ((*_c)->aorhash) & (_d->size - 1);
 	(*_c)->sl = sl;
+        LM_DBG("Putting contact into slot [%d]\n", sl);
 	slot_add(&_d->table[sl], *_c);
 	update_stat(_d->contacts, 1);
 	return 0;
@@ -263,11 +266,11 @@ void mem_timer_udomain(udomain_t* _d)
 	}
 }
 
-void lock_udomain(udomain_t* _d, str* _aor, str* _received_host, unsigned short received_port)
+void lock_udomain(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto)
 {
 	unsigned int sl;
 	
-	sl = get_hash_slot(_d, _aor, _received_host, received_port);
+	sl = get_hash_slot(_d, via_host, via_port, via_proto);
 
 #ifdef GEN_LOCK_T_PREFERED
 	lock_get(_d->table[sl].lock);
@@ -276,10 +279,10 @@ void lock_udomain(udomain_t* _d, str* _aor, str* _received_host, unsigned short
 #endif
 }
 
-void unlock_udomain(udomain_t* _d, str* _aor, str* _received_host, unsigned short received_port)
+void unlock_udomain(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto)
 {
 	unsigned int sl;
-	sl = get_hash_slot(_d, _aor, _received_host, received_port);
+	sl = get_hash_slot(_d, via_host, via_port, via_proto);
 #ifdef GEN_LOCK_T_PREFERED
 	lock_release(_d->table[sl].lock);
 #else
@@ -326,6 +329,13 @@ int update_rx_regsession(struct udomain* _d, str* session_id, struct pcontact* _
 	return 0;
 }
 
+/**
+ * assume locked before calling this - lock the contact slot...
+ * @param _d
+ * @param _ci
+ * @param _c
+ * @return 
+ */
 int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pcontact* _c) //TODO: should prob move this to pcontact
 {
 	int is_default = 1;
@@ -446,177 +456,102 @@ error:
  * @struct pontact** _c - contact to return to if found (null if not found)
  * @return 0 if found <>0 if not
  */
-int get_pcontact(udomain_t* _d, str* _contact, str* _received_host, int received_port, struct pcontact** _c) {
-	unsigned int sl, i, aorhash;
+int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _c) {
+	unsigned int sl, i, aorhash, params_len, has_rinstance=0;
 	struct pcontact* c;
-	ppublic_t* impu;
-	struct sip_uri needle_uri, impu_uri;
-	int port_match = 0;
-	str alias_host = {0, 0};
-	struct sip_uri contact_uri;
-	
-	if (parse_uri(_contact->s, _contact->len, &needle_uri) != 0 ) {
-		LM_ERR("failed to parse search URI [%.*s]\n", _contact->len, _contact->s);
-		return 1;
-	}
-
-	LM_DBG("Searching for contact in P-CSCF usrloc [%.*s]\n",
-				_contact->len,
-				_contact->s);
+	struct sip_uri needle_uri;
+        char *params, *sep;
+        str rinstance = {0, 0};
+        
+        LM_DBG("Searching for contact with AOR [%.*s] in P-CSCF usrloc based on VIA [%d://%.*s:%d] Received [%d://%.*s:%d], Search flag is %d\n",
+				contact_info->aor.len, contact_info->aor.s, contact_info->via_prot, contact_info->via_host.len, contact_info->via_host.s, contact_info->via_port,
+                contact_info->received_proto, contact_info->received_host.len, contact_info->received_host.s, contact_info->received_port, contact_info->searchflag);
 	
+            /* parse the uri in the NOTIFY */
+        if (contact_info->aor.len>0 && contact_info->aor.s){
+            LM_DBG("Have an AOR to search for\n");
+            if (parse_uri(contact_info->aor.s, contact_info->aor.len, &needle_uri) != 0) {
+                LM_ERR("Unable to parse contact aor in get_pcontact [%.*s]\n", contact_info->aor.len, contact_info->aor.s);
+                return 0;
+            }
+            LM_DBG("checking for rinstance");
+            /*check for alias - NAT */
+            params = needle_uri.sip_params.s;
+            params_len = needle_uri.sip_params.len;
+
+            while (params_len >= RINSTANCE_LEN) {
+                if (strncmp(params, RINSTANCE, RINSTANCE_LEN) == 0) {
+                    has_rinstance = 1;
+                    break;
+                }
+                sep = memchr(params, 59 /* ; */, params_len);
+                if (sep == NULL) {
+                    LM_DBG("no rinstance param\n");
+                    break;
+                } else {
+                    params_len = params_len - (sep - params + 1);
+                    params = sep + 1;
+                }
+            }
+            if (has_rinstance) {
+                rinstance.s = params + RINSTANCE_LEN;
+                rinstance.len = params_len - RINSTANCE_LEN;
+                sep = (char*)memchr(rinstance.s, 59 /* ; */, rinstance.len);
+                if (sep != NULL){
+                    rinstance.len = (sep-rinstance.s);
+                }
+                LM_DBG("rinstance found [%.*s]\n", rinstance.len, rinstance.s);
+            }
+        }
+             
+    
 	/* search in cache */
-	aorhash = get_aor_hash(_d, _contact, _received_host, received_port);
+	aorhash = get_aor_hash(_d, &contact_info->via_host, contact_info->via_port, contact_info->via_prot);
 	sl = aorhash & (_d->size - 1);
+        
+        LM_DBG("get_pcontact slot is [%d]\n", sl);
 	c = _d->table[sl].first;
 
 	for (i = 0; i < _d->table[sl].n; i++) {
-
-		if ((c->aorhash == aorhash) && (c->aor.len == _contact->len)
-				&& !memcmp(c->aor.s, _contact->s, _contact->len)) {
-			*_c = c;
-			return 0;
+            LM_DBG("comparing contact with aorhash [%u], aor [%.*s]\n", c->aorhash, c->aor.len, c->aor.s);
+		if ((c->aorhash == aorhash) && (c->contact_host.len == contact_info->via_host.len) && (memcmp(contact_info->via_host.s, c->contact_host.s, c->contact_host.len)==0) && (c->contact_port == contact_info->via_port)
+                        && (!(contact_info->searchflag&SEARCH_RECEIVED) || ((contact_info->searchflag&SEARCH_RECEIVED)
+                        && (c->received_host.len == contact_info->received_host.len && (memcmp(c->received_host.s, contact_info->received_host.s, contact_info->received_host.len)==0))
+                        && (c->received_port == contact_info->received_port)))) {
+                    LM_DBG("found contact with URI [%.*s]\n", c->aor.len, c->aor.s);
+                    if (has_rinstance) {
+                        LM_DBG("confirming rinstance is the same - search has [%.*s] and proposed found contact has [%.*s]",
+                                rinstance.len, rinstance.s, 
+                                c->rinstance.len, c->rinstance.s);
+                        if ((rinstance.len == c->rinstance.len) && memcmp(rinstance.s, c->rinstance.s, rinstance.len) != 0) {
+                            LM_DBG("rinstance does not match - not match here...\n");
+			    c = c->next;
+                            continue;
+                        }
+                    }
+                    *_c = c;
+                    return 0;
 		}
 		
-		if(match_contact_host_port) {
-		    LM_DBG("Comparing needle user@host:port [%.*s@%.*s:%d] and contact_user@contact_host:port [%.*s@%.*s:%d]\n", needle_uri.user.len, needle_uri.user.s, 
-			    needle_uri.host.len, needle_uri.host.s, needle_uri.port_no,
-			    c->contact_user.len, c->contact_user.s, c->contact_host.len, c->contact_host.s, c->contact_port);
-
-		    if((needle_uri.user.len == c->contact_user.len && (memcmp(needle_uri.user.s, c->contact_user.s, needle_uri.user.len) ==0)) &&
-			    (needle_uri.host.len == c->contact_host.len && (memcmp(needle_uri.host.s, c->contact_host.s, needle_uri.host.len) ==0)) &&
-			    (needle_uri.port_no == c->contact_port)) {
-			LM_DBG("Match!!\n");
-			*_c = c;
-			return 0;
-		    }
-		}
-		
-		LM_DBG("Searching for [%.*s] and comparing to [%.*s]\n", _contact->len, _contact->s, c->aor.len, c->aor.s);
-
-		/* hosts HAVE to match */
-		if (lookup_check_received && ((needle_uri.host.len != c->received_host.len) || (memcmp(needle_uri.host.s, c->received_host.s, needle_uri.host.len)!=0))) {
-			//can't possibly match
-			LM_DBG("Lookup failed for [%.*s <=> %.*s]\n", needle_uri.host.len, needle_uri.host.s, c->received_host.len, c->received_host.s);
-			c = c->next;
-			continue;
-		}
-
-		/* one of the ports must match, either the initial registered port, the received port, or one if the security ports (server) */
-		if ((needle_uri.port_no != c->contact_port) && (needle_uri.port_no != c->received_port)) {
-			//check security ports
-			if (c->security) {
-				switch (c->security->type) {
-				case SECURITY_IPSEC: {
-					ipsec_t* ipsec = c->security->data.ipsec;
-					if (ipsec) {
-						LM_DBG("security server port is %d\n", ipsec->port_us);
-						LM_DBG("security client port is %d\n", ipsec->port_uc);
-						if (ipsec->port_us == needle_uri.port_no) {
-							LM_DBG("security port mathes contact\n");
-							port_match = 1;
-						}
-					}
-					break;
-				}
-				case SECURITY_TLS:
-				case SECURITY_NONE:
-					LM_WARN("not implemented\n");
-					break;
-				}
-			}
-			if (!port_match && c->security_temp) {
-				switch (c->security_temp->type) {
-				case SECURITY_IPSEC: {
-					ipsec_t* ipsec = c->security_temp->data.ipsec;
-					if (ipsec) {
-						LM_DBG("temp security server port is %d\n", ipsec->port_us);
-						LM_DBG("temp security client port is %d\n", ipsec->port_uc);
-						if (ipsec->port_us == needle_uri.port_no) {
-							LM_DBG("temp security port mathes contact\n");
-							port_match = 1;
-						}
-					}
-					break;
-				}
-				case SECURITY_TLS:
-				case SECURITY_NONE:
-					LM_WARN("not implemented\n");
-					break;
-				}
-			}
-		} else {
-			port_match = 1;
-		}
-
-		if (!port_match){
-			LM_DBG("Port don't match: %d (contact) %d (received) != %d!\n",
-		c->contact_port, c->received_port, needle_uri.port_no);
-			c = c->next;
-			continue;
-		}
-
-		/* user parts must match (if not wildcarded) with either primary contact OR with any userpart in the implicit set (associated URIs).. */
-		if((needle_uri.user.len == c->contact_user.len) && (memcmp(needle_uri.user.s, c->contact_user.s,needle_uri.user.len) == 0)) {
-		    LM_DBG("Needle user part matches contact user part therefore this is a match\n");
-		    *_c = c;
-		    return 0;
-		} else if ((needle_uri.user.len == 1) && (memcmp(needle_uri.user.s, "*", 1) == 0)) { /*wild card*/
-		    LM_DBG("This a wild card user part - we must check if hosts match or needle host matches alias\n");
-		    if(memcmp(needle_uri.host.s, c->contact_host.s, needle_uri.host.len) == 0) {
-			LM_DBG("Needle host matches contact host therefore this is a match\n");
-			*_c = c;
-			return 0;
-		    } else if ((parse_uri(c->aor.s, c->aor.len, &contact_uri) == 0) && ((get_alias_host_from_contact(&contact_uri.params, &alias_host)) == 0) &&
-			    (memcmp(needle_uri.host.s, alias_host.s, alias_host.len) == 0)) {
-			LM_DBG("Needle host matches contact alias therefore this is a match\n");
-			*_c = c;
-			return 0;
-			
-		    }
-		}
-
-		/* check impus user parts */
-		impu = c->head;
-		while (impu) {
-			if (parse_uri(impu->public_identity.s, impu->public_identity.len, &impu_uri) != 0) {
-				LM_ERR("failed to parse IMPU URI [%.*s]...continuing\n", impu->public_identity.len, impu->public_identity.s);
-				impu = impu->next;
-				continue;
-			}
-			LM_DBG("comparing first %d chars of impu [%.*s] for contact userpart [%.*s]\n",
-					needle_uri.user.len,
-					impu->public_identity.len, impu->public_identity.s,
-					needle_uri.user.len, needle_uri.user.s);
-			if (needle_uri.user.len == impu_uri.user.len && (memcmp(needle_uri.user.s, impu_uri.user.s, impu_uri.user.len)==0)) {
-				*_c = c;
-				return 0;
-			}
-			impu = impu->next;
-		}
-
 		c = c->next;
 	}
+        
+        LM_DBG("contact not found in memory\n");
+        
 	return 1; /* Nothing found */
 }
 
 int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c) {
-	char c_contact[256], *p;
 	str s_contact;
-	int ret;
-
-	memset(c_contact, 0, 256);
-	strncpy(c_contact, "sip:*@", 6);	//prepend *@ to host to wildcard on user search
-	p = c_contact + 6;
-	memcpy(p, _host->s, _host->len);
-	p = p + _host->len;
-	*p = ':';
-	p++;
-	sprintf(p, "%d", _port);
-	s_contact.s = c_contact;
-	s_contact.len = strlen(c_contact);
+	pcontact_info_t contact_info;
+        int ret;
 	
 	LM_DBG("Trying to find contact by src with URI: [%.*s]\n", s_contact.len, s_contact.s);
-	ret = get_pcontact(_d, &s_contact, _host, _port, _c);
+        contact_info.via_host = *_host;
+        contact_info.via_port = _port;
+        contact_info.via_prot = _proto;
+                
+	ret = get_pcontact(_d, &contact_info, _c);
 
 	return ret;
 }
@@ -685,12 +620,10 @@ int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned s
 	return 0; /* Nothing found */
 }
 
-int delete_pcontact(udomain_t* _d, str* _aor, str* _received_host, int _received_port, struct pcontact* _c)
+int delete_pcontact(udomain_t* _d, /*str* _aor, str* _received_host, int _received_port,*/ struct pcontact* _c)
 {
 	if (_c==0) {
-		if (get_pcontact(_d, _aor, _received_host, _received_port, &_c) > 0) {
-			return 0;
-		}
+            return 0;
 	}
 
 	if (exists_ulcb_type(PCSCF_CONTACT_DELETE)) {
@@ -711,7 +644,7 @@ int delete_pcontact(udomain_t* _d, str* _aor, str* _received_host, int _received
  * \brief Convert database values into pcontact_info
  *
  * Convert database values into pcontact_info,
- * expects 12 rows (aor, contact, received, received_port, received_proto, rx_session_id_col
+ * expects 15 rows (aor, host, port, protocol, received, received_port, received_proto, rx_session_id_col
  * reg_state, expires, socket, service_routes_col, public_ids, path
  * \param vals database values
  * \param contact contact
@@ -720,44 +653,55 @@ int delete_pcontact(udomain_t* _d, str* _aor, str* _received_host, int _received
 static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 {
 	static pcontact_info_t ci;
-	static str received, path, rx_session_id, implicit_impus, tmpstr, service_routes;
+	static str host, received, path, rx_session_id, implicit_impus, tmpstr, service_routes;
 	static str *impu_list, *service_route_list;
 	int flag=0, n;
 	char *p, *q=0;
 
 	memset( &ci, 0, sizeof(pcontact_info_t));
 
-	received.s = (char*) VAL_STRING(vals + 2);
-	if (VAL_NULL(vals+2) || !received.s || !received.s[0]) {
-		received.len = 0;
-		received.s = 0;
+        host.s = (char*) VAL_STRING(vals + 1);
+	if (VAL_NULL(vals+1) || !host.s || !host.s[0]) {
+		host.len = 0;
+		host.s = 0;
+	} else {
+		host.len = strlen(host.s);
+	}
+	ci.via_host = host;
+        ci.via_port = VAL_INT(vals + 2);
+        ci.via_prot = VAL_INT(vals + 3);
+	received.s = (char*) VAL_STRING(vals + 4);
+	if (VAL_NULL(vals+4) || !received.s || !received.s[0]) {
+            LM_ERR("Empty received for contact [%.*s].... ignoring\n", contact->len, contact->s);
+            return 0;
 	} else {
 		received.len = strlen(received.s);
 	}
 	ci.received_host = received;
-	ci.received_port = VAL_INT(vals + 3);
-	ci.received_proto = VAL_INT(vals + 4);
+	ci.received_port = VAL_INT(vals + 5);
+	ci.received_proto = VAL_INT(vals + 6);
 
-	rx_session_id.s = (char*) VAL_STRING(vals + 5);
-	if (VAL_NULL(vals+5) || !rx_session_id.s || !rx_session_id.s[0]) {
+	rx_session_id.s = (char*) VAL_STRING(vals + 7);
+	if (VAL_NULL(vals+7) || !rx_session_id.s || !rx_session_id.s[0]) {
 		rx_session_id.len = 0;
 		rx_session_id.s = 0;
 	} else {
 		rx_session_id.len = strlen(rx_session_id.s);
 	}
 	ci.rx_regsession_id = &rx_session_id;
-	if (VAL_NULL(vals + 6)) {
+	if (VAL_NULL(vals + 8)) {
 		LM_ERR("empty registration state in DB\n");
 		return 0;
 	}
-	ci.reg_state = VAL_INT(vals + 6);
-	if (VAL_NULL(vals + 7)) {
+	ci.reg_state = VAL_INT(vals + 8);
+	
+        if (VAL_NULL(vals + 9)) {
 		LM_ERR("empty expire\n");
 		return 0;
 	}
-	ci.expires = VAL_TIME(vals + 7);
-	path.s  = (char*)VAL_STRING(vals+11);
-		if (VAL_NULL(vals+11) || !path.s || !path.s[0]) {
+	ci.expires = VAL_TIME(vals + 9);
+	path.s  = (char*)VAL_STRING(vals+13);
+		if (VAL_NULL(vals+13) || !path.s || !path.s[0]) {
 			path.len = 0;
 			path.s = 0;
 		} else {
@@ -766,8 +710,8 @@ static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 	ci.path = &path;
 
 	//public IDs - implicit set
-	implicit_impus.s = (char*) VAL_STRING(vals + 10);
-	if (!VAL_NULL(vals + 10) && implicit_impus.s && implicit_impus.s[0]) {
+	implicit_impus.s = (char*) VAL_STRING(vals + 12);
+	if (!VAL_NULL(vals + 12) && implicit_impus.s && implicit_impus.s[0]) {
 		//how many
 		n=0;
 		p = implicit_impus.s;
@@ -801,8 +745,8 @@ static inline pcontact_info_t* dbrow2info( db_val_t *vals, str *contact)
 	}
 
 	//service routes
-	service_routes.s = (char*) VAL_STRING(vals + 9);
-	if (!VAL_NULL(vals + 9) && service_routes.s && service_routes.s[0]) {
+	service_routes.s = (char*) VAL_STRING(vals + 11);
+	if (!VAL_NULL(vals + 11) && service_routes.s && service_routes.s[0]) {
 		//how many
 		n = 0;
 		p = service_routes.s;
@@ -851,9 +795,9 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 {
 	pcontact_info_t *ci;
 	db_row_t *row;
-	db_key_t columns[18];
+	db_key_t columns[15];
 	db1_res_t* res = NULL;
-	str aor, contact;
+	str aor;
 	int i, n;
 
 	pcontact_t* c;
@@ -862,17 +806,19 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 
 	columns[0] = &domain_col;
 	columns[1] = &aor_col;
-	columns[2] = &contact_col;
-	columns[3] = &received_col;
-	columns[4] = &received_port_col;
-	columns[5] = &received_proto_col;
-	columns[6] = &rx_session_id_col;
-	columns[7] = &reg_state_col;
-	columns[8] = &expires_col;
-	columns[9] = &socket_col;
-	columns[10] = &service_routes_col;
-	columns[11] = &public_ids_col;
-	columns[12] = &path_col;
+        columns[2] = &host_col;
+        columns[3] = &port_col;
+        columns[4] = &protocol_col;
+	columns[5] = &received_col;
+	columns[6] = &received_port_col;
+	columns[7] = &received_proto_col;
+	columns[8] = &rx_session_id_col;
+	columns[9] = &reg_state_col;
+	columns[10] = &expires_col;
+	columns[11] = &socket_col;
+	columns[12] = &service_routes_col;
+	columns[13] = &public_ids_col;
+	columns[14] = &path_col;
 
 	if (ul_dbf.use_table(_c, _d->name) < 0) {
 		LM_ERR("sql use_table failed\n");
@@ -884,7 +830,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 #endif
 
 	if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
-		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 13, 0, 0) < 0) {
+		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 15, 0, 0) < 0) {
 			LM_ERR("db_query (1) failed\n");
 			return -1;
 		}
@@ -893,7 +839,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 			return -1;
 		}
 	} else {
-		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 13, 0, &res) < 0) {
+		if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 15, 0, &res) < 0) {
 			LM_ERR("db_query failed\n");
 			return -1;
 		}
@@ -919,21 +865,21 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d)
 				continue;
 			}
 			aor.len = strlen(aor.s);
-
-			ci = dbrow2info( ROW_VALUES(row)+1, &contact);
-			if (ci==0) {
-				LM_ERR("usrloc record for %.*s in table %s\n",
-						aor.len, aor.s, _d->name->s);
-				continue;
-			}
-			lock_udomain(_d, &aor, &ci->received_host, ci->received_port);
+                        ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
+                        if (!ci) {
+                            LM_WARN("Failed to get contact info from DB.... continuing...\n");
+                            continue;
+                        }
+			lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
 
 			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
 				LM_ERR("inserting contact failed\n");
-				unlock_udomain(_d, &aor, &ci->received_host, ci->received_port);
+				unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
 				goto error1;
 			}
-			unlock_udomain(_d, &aor, &ci->received_host, ci->received_port);
+                        //c->flags = c->flags|(1<<FLAG_READFROMDB);
+                        //TODO: need to subscribe to s-cscf for first public identity
+			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
 		}
 
 		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
@@ -961,4 +907,93 @@ error1:
 	return -1;
 }
 
+pcontact_t* db_load_pcontact(db1_con_t* _c, udomain_t* _d, str *_aor)
+{
+	pcontact_info_t *ci;
+	db_key_t columns[15];
+	db_key_t keys[1];
+	db_val_t vals[1];
+	db1_res_t* res = NULL;
+	db_row_t *row;
+	int i;
+        str aor;
+
+	pcontact_t* c;
+
+	keys[0] = &aor_col;
+	vals[0].type = DB1_STR;
+	vals[0].nul = 0;
+	vals[0].val.str_val = *_aor;
+
+        columns[0] = &domain_col;
+	columns[1] = &aor_col;
+        columns[2] = &host_col;
+        columns[3] = &port_col;
+        columns[4] = &protocol_col;
+	columns[5] = &received_col;
+	columns[6] = &received_port_col;
+	columns[7] = &received_proto_col;
+	columns[8] = &rx_session_id_col;
+	columns[9] = &reg_state_col;
+	columns[10] = &expires_col;
+	columns[11] = &socket_col;
+	columns[12] = &service_routes_col;
+	columns[13] = &public_ids_col;
+	columns[14] = &path_col;
+        
+        LM_DBG("Querying database for P-CSCF contact [%.*s]\n", _aor->len, _aor->s);
+        
+	if (ul_dbf.use_table(_c, _d->name) < 0) {
+		LM_ERR("failed to use table %.*s\n", _d->name->len, _d->name->s);
+		return 0;
+	}
+
+	if (ul_dbf.query(_c, keys, 0, vals, columns, 1, 15, 0, &res) < 0) {
+		LM_ERR("db_query failed\n");
+		return 0;
+	}
+
+	if (RES_ROW_N(res) == 0) {
+		LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
+		ul_dbf.free_result(_c, res);
+		return 0;
+	}
+
+	for(i = 0; i < RES_ROW_N(res); i++) {
+                        row = RES_ROWS(res) + i;
+
+			aor.s = (char*) VAL_STRING(ROW_VALUES(row) + 1);
+			if (VAL_NULL(ROW_VALUES(row) + 1) || aor.s == 0 || aor.s[0] == 0) {
+				LM_CRIT("empty aor record in table %s...skipping\n", _d->name->s);
+				continue;
+			}
+			aor.len = strlen(aor.s);
+                        ci = dbrow2info(ROW_VALUES(row) + 1, &aor);
+                        if (!ci) {
+                            LM_WARN("Failed to get contact info from DB.... continuing...\n");
+                            continue;
+                        }
+			lock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+
+			if ( (mem_insert_pcontact(_d, &aor, ci, &c)) != 0) {
+				LM_ERR("inserting contact failed\n");
+				unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+				goto error;
+			}
+                        //c->flags = c->flags|(1<<FLAG_READFROMDB);
+                        //TODO: need to subscribe to s-cscf for first public identity
+			unlock_udomain(_d, &ci->via_host, ci->via_port, ci->via_prot);
+	}
+
+	ul_dbf.free_result(_c, res);
+
+	return c;
+
+error:
+        free_pcontact(c);
+
+	ul_dbf.free_result(_c, res);
+	return 0;
+}
+
 

+ 4 - 4
modules/ims_usrloc_pcscf/udomain.h

@@ -67,8 +67,8 @@ void mem_timer_udomain(udomain_t* _d);
 int mem_insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _c);
 void mem_delete_pcontact(udomain_t* _d, struct pcontact* _r);
 
-void lock_udomain(udomain_t* _d, str *_aor, str* _received_host, unsigned short int received_port);
-void unlock_udomain(udomain_t* _d, str *_aor, str* _received_host, unsigned short int received_port);
+void lock_udomain(udomain_t* _d, str* _via_host, unsigned short via_port, unsigned short via_protot);
+void unlock_udomain(udomain_t* _d, str* _via_host, unsigned short via_port, unsigned short via_proto);
 
 void lock_ulslot(udomain_t* _d, int i);
 void unlock_ulslot(udomain_t* _d, int i);
@@ -76,10 +76,10 @@ void unlock_ulslot(udomain_t* _d, int i);
 int update_rx_regsession(struct udomain* _d, str* session_id, struct pcontact* _c);
 int update_pcontact(struct udomain* _d, struct pcontact_info* _ci, struct pcontact* _c);
 int insert_pcontact(struct udomain* _d, str* _contact, struct pcontact_info* _ci, struct pcontact** _r);
-int get_pcontact(udomain_t* _d, str* _aor, str* _received_host, int received_port, struct pcontact** _r);
+int get_pcontact(udomain_t* _d, pcontact_info_t* contact_info, struct pcontact** _r);
 int get_pcontact_by_src(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c);
 int assert_identity(udomain_t* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity);
-int delete_pcontact(udomain_t* _d, str* _aor, str* _received_host, int _received_port, struct pcontact* _r);
+int delete_pcontact(udomain_t* _d, struct pcontact* _r);
 int update_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c);
 int update_temp_security(udomain_t* _d, security_type _t, security_t* _s, struct pcontact* _c);
 

+ 4 - 0
modules/ims_usrloc_pcscf/ul_mod.c

@@ -72,6 +72,9 @@ static int child_init(int rank);                    /*!< Per-child init function
 extern int bind_usrloc(usrloc_api_t* api);
 extern int ul_locks_no;
 
+
+int expires_grace = 3600;   //default is a grace period of 1 hour - after this contact is removed from P
+
 /*
  * Module parameters and their default values
  */
@@ -114,6 +117,7 @@ static param_export_t params[] = {
 	{"hashing_type",		INT_PARAM, &hashing_type	},
 	{"lookup_check_received",		INT_PARAM, &lookup_check_received	},
 	{"match_contact_host_port",		INT_PARAM, &match_contact_host_port	},
+        {"expires_grace",		INT_PARAM, &expires_grace	},
 
 	{0, 0, 0}
 };

+ 8 - 46
modules/ims_usrloc_pcscf/usrloc.c

@@ -72,7 +72,6 @@ int bind_usrloc(usrloc_api_t* api) {
 	api->insert_pcontact = insert_pcontact;
 	api->delete_pcontact = delete_pcontact;
 	api->get_pcontact = get_pcontact;
-	api->get_pcontact_by_src = get_pcontact_by_src;
 	api->assert_identity = assert_identity;
 	api->update_pcontact = update_pcontact;
 	api->update_rx_regsession = update_rx_regsession;
@@ -132,58 +131,21 @@ int get_alias_host_from_contact(str *contact_uri_params, str *alias_host) {
 
 
 /* return the slot id for inserting contacts in the hash */
-unsigned int get_hash_slot(udomain_t* _d, str* _aor, str* received_host, int received_port) {
-    struct sip_uri contact_uri;
+unsigned int get_hash_slot(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto) {
     unsigned int sl;
-    str alias_host = {0, 0};
 
-    if ((hashing_type == 0) /*use full AOR for hash*/ || (parse_uri(_aor->s, _aor->len, &contact_uri) != 0)) {
-	if (hashing_type != 0) {
-	    LM_DBG("Unable to get contact host:port from contact header [%.*s]... falling back to full AOR\n", _aor->len, _aor->s);
-	}
-	sl = core_hash(_aor, 0, _d->size);
-    } else {
-	if ( received_host && (memcmp(contact_uri.host.s, received_host->s, received_host->len) != 0)) {
-	    LM_DBG("Looks like this contact is natted - contact URI: [%.*s] but came from received_host: [%.*s] so will use received_host for hash\n", contact_uri.host.len, contact_uri.host.s,
-		    received_host->len, received_host->s);
-	    sl = core_hash(received_host, 0, _d->size);
-	} else if (((get_alias_host_from_contact(&contact_uri.params, &alias_host)) == 0 && (memcmp(contact_uri.host.s, alias_host.s, alias_host.len) != 0))) {
-	    LM_DBG("Looks like this contact is natted - as it has alias [%.*s] different from contact URI [%.*s] so will use alias for hash\n", 
-		    alias_host.len, alias_host.s, contact_uri.host.len, contact_uri.host.s);
-	    sl = core_hash(&alias_host, 0, _d->size);
-	}else {
-	    LM_DBG("using host for hash [%.*s]\n", contact_uri.host.len, contact_uri.host.s);
-	    sl = core_hash(&contact_uri.host, 0, _d->size);
-	}
-    } 
+    sl = get_aor_hash(_d, via_host, via_port, via_proto);
+    sl = sl & (_d->size - 1) ;
     LM_DBG("Returning hash slot: [%d]\n", sl);
+
     return sl;
 }
 
-unsigned int get_aor_hash(udomain_t* _d, str* _aor, str* received_host, int received_port) {
-    struct sip_uri contact_uri;
+unsigned int get_aor_hash(udomain_t* _d, str* via_host, unsigned short via_port, unsigned short via_proto) {
     unsigned int aorhash;
-    str alias_host = {0, 0};
+        
+    aorhash = core_hash(via_host, 0, 0);
+    LM_DBG("Returning hash: [%u]\n", aorhash);
 
-    if ((hashing_type == 0) /*use full AOR for hash*/ || (parse_uri(_aor->s, _aor->len, &contact_uri) != 0)) {
-	if (hashing_type != 0) {
-	    LM_DBG("Unable to get contact host:port from contact header [%.*s]... falling back to full AOR\n", _aor->len, _aor->s);
-	}
-	aorhash = core_hash(_aor, 0, 0);
-    } else {
-	if ( received_host && (memcmp(contact_uri.host.s, received_host->s, received_host->len) != 0)) {
-	    LM_DBG("Looks like this contact is natted - contact URI: [%.*s] but came from received_host: [%.*s] so will use received_host for hash\n", contact_uri.host.len, contact_uri.host.s,
-		    received_host->len, received_host->s);
-	    aorhash = core_hash(received_host, 0, 0);
-	} else if (((get_alias_host_from_contact(&contact_uri.params, &alias_host)) == 0 && (memcmp(contact_uri.host.s, alias_host.s, alias_host.len) != 0))) {
-	    LM_DBG("Looks like this contact is natted - as it has alias [%.*s] different from contact URI [%.*s] so will use alias for hash\n", 
-		    alias_host.len, alias_host.s, contact_uri.host.len, contact_uri.host.s);
-	    aorhash = core_hash(&alias_host, 0, 0);
-	}else {
-	    LM_DBG("using host for hash [%.*s]\n", contact_uri.host.len, contact_uri.host.s);
-	    aorhash = core_hash(&contact_uri.host, 0, 0);
-	}
-    } 
-    LM_DBG("Returning hash slot: [%d]\n", aorhash);
     return aorhash;
 }

+ 144 - 128
modules/ims_usrloc_pcscf/usrloc.h

@@ -59,172 +59,190 @@
 #define WRITE_BACK    2		//not implemented yet
 #define DB_ONLY	      3		//not implemented yet
 
+#define SEARCH_NORMAL 0
+#define SEARCH_RECEIVED 1
+
+#define ALIAS        "alias="
+#define ALIAS_LEN (sizeof(ALIAS) - 1)
+
+#define RINSTANCE   "rinstance="
+#define RINSTANCE_LEN (sizeof(RINSTANCE) - 1)
+
 #define VALID_CONTACT(c, t)   ((c->expires>t) || (c->expires==0))
 
-struct hslot;		/*!< Hash table slot */
+struct hslot; /*!< Hash table slot */
 struct socket_info;
 
 int get_alias_host_from_contact(str *contact_uri_params, str *alias_host);
 
 struct udomain {
-	str* name;                 /*!< Domain name (NULL terminated) */
-	int size;                  /*!< Hash table size */
-	struct hslot* table;       /*!< Hash table - array of collision slots */
-	/* statistics */
-	stat_var *contacts;        /*!< no of registered contacts */
-	stat_var *expired;         /*!< no of expires */
+    str* name; /*!< Domain name (NULL terminated) */
+    int size; /*!< Hash table size */
+    struct hslot* table; /*!< Hash table - array of collision slots */
+    /* statistics */
+    stat_var *contacts; /*!< no of registered contacts */
+    stat_var *expired; /*!< no of expires */
 };
 typedef struct udomain udomain_t;
 
 /** Public Identity Structure */
 typedef struct {
-	char barring; /**< Barring state									*/
-	str public_identity; /**< Public Identity string							*/
-	str wildcarded_psi; /** if exists is the wildcarded psi					*/
+    char barring; /**< Barring state									*/
+    str public_identity; /**< Public Identity string							*/
+    str wildcarded_psi; /** if exists is the wildcarded psi					*/
 } ims_public_identity;
 
 /** TLS SA Information */
 typedef struct tls {
-	unsigned short port_tls; 	/**< Port UE TLS						*/
-	unsigned long session_hash;
+    unsigned short port_tls; /**< Port UE TLS						*/
+    unsigned long session_hash;
 } tls_t;
 
 /** IPSec SA Information */
 typedef struct ipsec {
-	unsigned int spi_uc; 		/**< SPI Client to use					*/
-	unsigned int spi_us; 		/**< SPI Server to use					*/
-	unsigned int spi_pc; 		/**< SPI Client to use					*/
-	unsigned int spi_ps; 		/**< SPI Server to use					*/
-	unsigned short port_uc; 	/**< Port UE Client						*/
-	unsigned short port_us; 	/**< Port UE Server						*/
-
-	str ealg; 					/**< Cypher Algorithm - ESP				*/
-	str r_ealg; 				/**< received Cypher Algorithm - ESP	*/
-	str ck; 					/**< Cypher Key							*/
-	str alg; 					/**< Integrity Algorithm - AH			*/
-	str r_alg; 					/**<received Integrity Algorithm - AH	*/
-	str ik; 					/**< Integrity Key						*/
-	str prot; 					/**< Protocol (ah/esp) */
-	str mod; 					/**< Mode (transport/tunnel) */
+    unsigned int spi_uc; /**< SPI Client to use					*/
+    unsigned int spi_us; /**< SPI Server to use					*/
+    unsigned int spi_pc; /**< SPI Client to use					*/
+    unsigned int spi_ps; /**< SPI Server to use					*/
+    unsigned short port_uc; /**< Port UE Client						*/
+    unsigned short port_us; /**< Port UE Server						*/
+
+    str ealg; /**< Cypher Algorithm - ESP				*/
+    str r_ealg; /**< received Cypher Algorithm - ESP	*/
+    str ck; /**< Cypher Key							*/
+    str alg; /**< Integrity Algorithm - AH			*/
+    str r_alg; /**<received Integrity Algorithm - AH	*/
+    str ik; /**< Integrity Key						*/
+    str prot; /**< Protocol (ah/esp) */
+    str mod; /**< Mode (transport/tunnel) */
 } ipsec_t;
 
 typedef enum sec_type {
-	SECURITY_NONE = 0,
-	SECURITY_IPSEC = 1,
-	SECURITY_TLS = 2,
+    SECURITY_NONE = 0,
+    SECURITY_IPSEC = 1,
+    SECURITY_TLS = 2,
 } security_type;
 
 typedef struct security {
-	str sec_header; 		/**< Security Header value 				*/
-	security_type type; 	/**< Type of security in use			*/
-
-	union {
-		ipsec_t *ipsec; 	/**< IPSec SA information, if any		*/
-		tls_t *tls;			/**< TLS SA information, if any		*/
-	} data;
-	float q;
+    str sec_header; /**< Security Header value 				*/
+    security_type type; /**< Type of security in use			*/
+
+    union {
+        ipsec_t *ipsec; /**< IPSec SA information, if any		*/
+        tls_t *tls; /**< TLS SA information, if any		*/
+    } data;
+    float q;
 } security_t;
 
 typedef struct udomain_head {
-	str* name;
+    str* name;
 } udomain_head_t;
 
 /* public identity structure. To be associated with a contact */
 typedef struct ppublic {
-	str public_identity;					/**< Public identity */
-	char is_default;						/**< is this the default identity for the contact */
-	struct ppublic* next;
-	struct ppublic* prev;
+    str public_identity; /**< Public identity */
+    char is_default; /**< is this the default identity for the contact */
+    struct ppublic* next;
+    struct ppublic* prev;
 } ppublic_t;
 
 /** Enumeration for public identity Registration States */
 enum pcontact_reg_states {
-	PCONTACT_NOT_REGISTERED 	= 0, 			/**< User not-registered, no profile stored	*/
-	PCONTACT_REGISTERED 		= 1, 			/**< User registered						*/
-	PCONTACT_REG_PENDING 		= -1,			/**< User not-registered, profile stored	*/
-	PCONTACT_REG_PENDING_AAR 	= -2,			/**< User not-registered, profile stored, AAR sent	*/
-	PCONTACT_DEREGISTERED 		= -3,
-    PCONTACT_DEREG_PENDING_PUBLISH	= -4
+    PCONTACT_NOT_REGISTERED = 0, /**< User not-registered, no profile stored	*/
+    PCONTACT_REGISTERED = 1, /**< User registered						*/
+    PCONTACT_REG_PENDING = -1, /**< User not-registered, profile stored	*/
+    PCONTACT_REG_PENDING_AAR = -2, /**< User not-registered, profile stored, AAR sent	*/
+    PCONTACT_DEREGISTERED = -3,
+    PCONTACT_DEREG_PENDING_PUBLISH = -4
 };
 
 static inline char* reg_state_to_string(enum pcontact_reg_states reg_state) {
-	switch (reg_state) {
-		case PCONTACT_NOT_REGISTERED:
-			return "not registered";
-		case PCONTACT_REGISTERED:
-			return "registered";
-		case PCONTACT_REG_PENDING:
-			return "registration pending";
-		case PCONTACT_DEREGISTERED:
-			return "unregistered";
-		case PCONTACT_DEREG_PENDING_PUBLISH:
-			return "deregistration pending, publish sent";
-		case PCONTACT_REG_PENDING_AAR:
-			return "registration pending, aar sent";
-		default:
-			return "unknown";
-	}
+    switch (reg_state) {
+        case PCONTACT_NOT_REGISTERED:
+            return "not registered";
+        case PCONTACT_REGISTERED:
+            return "registered";
+        case PCONTACT_REG_PENDING:
+            return "registration pending";
+        case PCONTACT_DEREGISTERED:
+            return "unregistered";
+        case PCONTACT_DEREG_PENDING_PUBLISH:
+            return "deregistration pending, publish sent";
+        case PCONTACT_REG_PENDING_AAR:
+            return "registration pending, aar sent";
+        default:
+            return "unknown";
+    }
 }
+
 typedef struct pcontact_info {
-	str received_host;
-	unsigned short received_port;
-	unsigned short received_proto; /*!< from transport */
-	str* path;
-	time_t expires;
-	str* callid;
-	str* public_ids;
-	int num_public_ids;
-	str* service_routes;
-	int num_service_routes;
-	str* rx_regsession_id;
-	enum pcontact_reg_states reg_state;
-}pcontact_info_t;
+    unsigned short searchflag; /*!search flag - what to search on */
+    str aor; /* contact uri */
+    str via_host;
+    unsigned short via_port;
+    unsigned short via_prot;
+    str received_host;
+    unsigned short received_port;
+    unsigned short received_proto; /*!< from transport */
+    str* path;
+    time_t expires;
+    str* callid;
+    str* public_ids;
+    int num_public_ids;
+    str* service_routes;
+    int num_service_routes;
+    str* rx_regsession_id;
+    enum pcontact_reg_states reg_state;
+} pcontact_info_t;
 
 /*! \brief
  * Basic hash table element
  */
 typedef struct pcontact {
-	unsigned int aorhash; 					/*!< Hash over address of record */
-	unsigned int sl;                                        /*!< slot number */
-	struct hslot* slot; 					/*!< Collision slot in the hash table array we belong to */
-	str* domain; 							/*!< Pointer to domain we belong to (null terminated string) */
-	str aor;			 					/*!< Address of record */
-	str contact_host;						/*!< host part of contact */
-	str contact_user;						/*!< user part of contact */
-	unsigned short contact_port;			/*!< port part of contact */
-	str callid;								/*!< Call-ID */
-	str received_host;						/*!< host part of src address where register came from */
-	unsigned short received_port;			/*!< port register was received from */
-	unsigned short received_proto; 			/*!< from transport */ ;
-	str path;               				/*!< Path header */
-	str rx_session_id;						/*!< Rx Session ID for registration Rx AF session - not used if not using diameter_rx */
-	enum pcontact_reg_states reg_state;		/*!< Reg state of contact */
-	time_t expires;							/*!< expires time for contact */
-	str* service_routes;					/*!< Array of service routes */
-	unsigned short num_service_routes;		/*!< Number of service routes */
-	security_t *security;	  				/**< Security-Client Information		*/
-	security_t *security_temp;	    		/**< Security-Client Information (temp)	*/
-	ppublic_t* head;						/*!< list of associated public identities */
-	ppublic_t* tail;
-	struct socket_info *sock; 				/*!< received socket */
-	struct ulcb_head_list cbs;				/*!< contact callback list */
-	struct pcontact* prev; 					/*!< Next item in the hash entry */
-	struct pcontact* next; 					/*!< Previous item in the hash entry */
+    unsigned int aorhash; /*!< Hash over address of record */
+    unsigned int sl; /*!< slot number */
+    struct hslot* slot; /*!< Collision slot in the hash table array we belong to */
+    str* domain; /*!< Pointer to domain we belong to (null terminated string) */
+    str aor; /*!< Address of record */
+    str rinstance;
+    str contact_host; /*!< host part of contact */
+    str contact_user; /*!< user part of contact */
+    unsigned short contact_port; /*!< port part of contact */
+    str callid; /*!< Call-ID */
+    str received_host; /*!< host part of src address where register came from */
+    unsigned short received_port; /*!< port register was received from */
+    unsigned short received_proto;
+    /*!< from transport */;
+    str via_host;
+    unsigned short via_port;
+    unsigned short via_proto;
+    str path; /*!< Path header */
+    str rx_session_id; /*!< Rx Session ID for registration Rx AF session - not used if not using diameter_rx */
+    enum pcontact_reg_states reg_state; /*!< Reg state of contact */
+    time_t expires; /*!< expires time for contact */
+    str* service_routes; /*!< Array of service routes */
+    unsigned short num_service_routes; /*!< Number of service routes */
+    security_t *security; /**< Security-Client Information		*/
+    security_t *security_temp; /**< Security-Client Information (temp)	*/
+    ppublic_t* head; /*!< list of associated public identities */
+    ppublic_t* tail;
+    struct socket_info *sock; /*!< received socket */
+    struct ulcb_head_list cbs; /*!< contact callback list */
+    struct pcontact* prev; /*!< Next item in the hash entry */
+    struct pcontact* next; /*!< Previous item in the hash entry */
 } pcontact_t;
 
-typedef int (*get_pcontact_t)(struct udomain* _d, str* _contact, str* _received_host, int received_port, struct pcontact** _c);
-
-typedef int (*get_pcontact_by_src_t)(struct udomain* _d, str * _host, unsigned short _port, unsigned short _proto, struct pcontact** _c);
+typedef int (*get_pcontact_t)(struct udomain* _d, pcontact_info_t* contact_info, struct pcontact** _c);
 
 typedef int (*assert_identity_t)(struct udomain* _d, str * _host, unsigned short _port, unsigned short _proto, str * _identity);
 
 typedef int (*insert_pcontact_t)(struct udomain* _d, str* _aor, struct pcontact_info* ci, struct pcontact** _c);
-typedef int (*delete_pcontact_t)(struct udomain* _d, str* _aor, str* _received_host, int received_port, struct pcontact* _c);
+typedef int (*delete_pcontact_t)(struct udomain* _d, struct pcontact* _c);
 typedef int (*update_pcontact_t)(struct udomain* _d, struct pcontact_info* ci, struct pcontact* _c);
 typedef int (*update_rx_regsession_t)(struct udomain* _d, str* session_id, struct pcontact* _c);
 
-typedef void (*lock_udomain_t)(struct udomain* _d, str *_aor, str* _received_host, unsigned short received_port);
-typedef void (*unlock_udomain_t)(struct udomain* _d, str *_aor, str* _received_host, unsigned short received_port);
+typedef void (*lock_udomain_t)(struct udomain* _d, str *via_host, unsigned short via_port, unsigned short via_proto);
+typedef void (*unlock_udomain_t)(struct udomain* _d, str *via_host, unsigned short via_port, unsigned short via_proto);
 typedef int (*register_udomain_t)(const char* _n, struct udomain** _d);
 typedef int (*get_udomain_t)(const char* _n, udomain_t** _d);
 typedef int (*get_all_ucontacts_t)(void* buf, int len, unsigned int flags, unsigned int part_idx, unsigned int part_max);
@@ -233,31 +251,29 @@ typedef int (*get_all_ucontacts_t)(void* buf, int len, unsigned int flags, unsig
 typedef int (*update_security_t)(struct udomain* _d, security_type _t, security_t* _s, struct pcontact* _c);
 typedef int (*update_temp_security_t)(struct udomain* _d, security_type _t, security_t* _s, struct pcontact* _c);
 
-
 /*! usrloc API export structure */
 typedef struct usrloc_api {
-	int use_domain; /*! use_domain module parameter */
-	int db_mode; /*! db_mode module parameter */
+    int use_domain; /*! use_domain module parameter */
+    int db_mode; /*! db_mode module parameter */
 
-	register_udomain_t register_udomain;
-	get_udomain_t get_udomain;
-	lock_udomain_t lock_udomain;
-	unlock_udomain_t unlock_udomain;
+    register_udomain_t register_udomain;
+    get_udomain_t get_udomain;
+    lock_udomain_t lock_udomain;
+    unlock_udomain_t unlock_udomain;
 
-	insert_pcontact_t insert_pcontact;
-	delete_pcontact_t delete_pcontact;
-	get_pcontact_t get_pcontact;
-	get_pcontact_by_src_t get_pcontact_by_src;
-	assert_identity_t assert_identity;
+    insert_pcontact_t insert_pcontact;
+    delete_pcontact_t delete_pcontact;
+    get_pcontact_t get_pcontact;
+    assert_identity_t assert_identity;
 
-	update_pcontact_t update_pcontact;
-	update_rx_regsession_t update_rx_regsession;
-	get_all_ucontacts_t get_all_ucontacts;
+    update_pcontact_t update_pcontact;
+    update_rx_regsession_t update_rx_regsession;
+    get_all_ucontacts_t get_all_ucontacts;
 
-	update_security_t update_security;
-	update_temp_security_t update_temp_security;
+    update_security_t update_security;
+    update_temp_security_t update_temp_security;
 
-	register_ulcb_t register_ulcb;
+    register_ulcb_t register_ulcb;
 } usrloc_api_t;
 
 /*! usrloc API export bind function */

+ 25 - 14
modules/ims_usrloc_pcscf/usrloc_db.c

@@ -12,11 +12,14 @@
 str id_col	        	= str_init(ID_COL);
 str domain_col			= str_init(DOMAIN_COL);
 str aor_col		    	= str_init(AOR_COL);
-str contact_col		    = str_init(CONTACT_COL);
+str host_col                    = str_init(HOST_COL);
+str port_col                    = str_init(PORT_COL);
+str protocol_col 		= str_init(PROTOCOL_COL);
 str received_col    	= str_init(RECEIVED_COL);
 str received_port_col	= str_init(RECEIVED_PORT_COL);
 str received_proto_col	= str_init(RECEIVED_PROTO_COL);
 str path_col			= str_init(PATH_COL);
+str rinstance_col       = str_init(RINSTANCE_COL);
 str rx_session_id_col	= str_init(RX_SESSION_ID_COL);
 str reg_state_col		= str_init(REG_STATE_COL);
 str expires_col			= str_init(EXPIRES_COL);
@@ -24,7 +27,6 @@ str service_routes_col	= str_init(SERVICE_ROUTES_COL);
 str socket_col			= str_init(SOCKET_COL);
 str public_ids_col		= str_init(PUBLIC_IDS_COL);
 str security_type_col 	= str_init(SECURITY_TYPE_COL);
-str protocol_col 		= str_init(PROTOCOL_COL);
 str mode_col			= str_init(MODE_COL);
 str ck_col				= str_init(CK_COL);
 str ik_col 				= str_init(IK_COL);
@@ -227,51 +229,60 @@ int db_insert_pcontact(struct pcontact* _c)
 	str empty_str = str_init("");
 	str impus, service_routes;
 
-	db_key_t keys[13] = {
-							&domain_col,
-				&aor_col, 			&contact_col,
+	db_key_t keys[16] = {
+				&domain_col,
+				&aor_col,
 				&received_col,
 				&received_port_col,	&received_proto_col,
-				&path_col,			&rx_session_id_col,
-				&reg_state_col,
+				&path_col,		&rinstance_col,
+                                &rx_session_id_col,	&reg_state_col,
 				&expires_col,		&service_routes_col,
-				&socket_col,		&public_ids_col
+				&socket_col,		&public_ids_col, &host_col, &port_col, &protocol_col
 	};
-	db_val_t values[13];
+	db_val_t values[16];
 
 	VAL_TYPE(GET_FIELD_IDX(values, LP_DOMAIN_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_AOR_IDX)) = DB1_STR;
-	VAL_TYPE(GET_FIELD_IDX(values, LP_CONTACT_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_RECEIVED_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_RECEIVED_PORT_IDX)) = DB1_INT;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_RECEIVED_PROTO_IDX)) = DB1_INT;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_PATH_IDX)) = DB1_STR;
+        VAL_TYPE(GET_FIELD_IDX(values, LP_RINSTANCE_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_RX_SESSION_ID_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_REG_STATE_IDX)) = DB1_INT;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_EXPIRES_IDX)) = DB1_DATETIME;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_SERVICE_ROUTES_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_SOCKET_IDX)) = DB1_STR;
 	VAL_TYPE(GET_FIELD_IDX(values, LP_PUBLIC_IPS_IDX)) = DB1_STR;
+        VAL_TYPE(GET_FIELD_IDX(values, LP_HOST_IDX)) = DB1_STR;
+        VAL_TYPE(GET_FIELD_IDX(values, LP_PORT_IDX)) = DB1_INT;
+        VAL_TYPE(GET_FIELD_IDX(values, LP_PROTOCOL_IDX)) = DB1_INT;
+        
 
 	SET_STR_VALUE(GET_FIELD_IDX(values, LP_DOMAIN_IDX), (*_c->domain));
 	SET_STR_VALUE(GET_FIELD_IDX(values, LP_AOR_IDX), _c->aor);	//TODO: need to clean AOR
-	SET_STR_VALUE(GET_FIELD_IDX(values, LP_CONTACT_IDX), _c->aor);
 	SET_STR_VALUE(GET_FIELD_IDX(values, LP_RECEIVED_IDX), _c->received_host);
+        SET_STR_VALUE(GET_FIELD_IDX(values, LP_HOST_IDX), _c->via_host);
 
 	SET_PROPER_NULL_FLAG((*_c->domain), values, LP_DOMAIN_IDX);
 	SET_PROPER_NULL_FLAG(_c->aor, values, LP_AOR_IDX);
-	SET_PROPER_NULL_FLAG(_c->aor, values, LP_CONTACT_IDX);
 	SET_PROPER_NULL_FLAG(_c->received_host, values, LP_RECEIVED_IDX);
+        SET_PROPER_NULL_FLAG(_c->via_host, values, LP_HOST_IDX);
 
 	VAL_INT(GET_FIELD_IDX(values, LP_RECEIVED_PORT_IDX)) = _c->received_port;
 	VAL_INT(GET_FIELD_IDX(values, LP_RECEIVED_PROTO_IDX)) = _c->received_proto;
 	VAL_NULL(GET_FIELD_IDX(values, LP_RECEIVED_PORT_IDX)) = 0;
 	VAL_NULL(GET_FIELD_IDX(values, LP_RECEIVED_PROTO_IDX)) = 0;
+        VAL_INT(GET_FIELD_IDX(values, LP_PORT_IDX)) = _c->via_port;
+        VAL_INT(GET_FIELD_IDX(values, LP_PROTOCOL_IDX)) = _c->via_proto;
+        VAL_NULL(GET_FIELD_IDX(values, LP_PORT_IDX)) = 0;
+        VAL_NULL(GET_FIELD_IDX(values, LP_PROTOCOL_IDX)) = 0;
 
 	SET_STR_VALUE(GET_FIELD_IDX(values, LP_PATH_IDX), _c->path);
+        SET_STR_VALUE(GET_FIELD_IDX(values, LP_RINSTANCE_IDX), _c->rinstance);
 	SET_STR_VALUE(GET_FIELD_IDX(values, LP_RX_SESSION_ID_IDX), _c->rx_session_id);
-
 	SET_PROPER_NULL_FLAG(_c->path, values, LP_PATH_IDX);
+        SET_PROPER_NULL_FLAG(_c->rinstance, values, LP_RINSTANCE_IDX);
 	SET_PROPER_NULL_FLAG(_c->rx_session_id, values, LP_RX_SESSION_ID_IDX);
 
 	VAL_DOUBLE(GET_FIELD_IDX(values, LP_REG_STATE_IDX)) = _c->reg_state;
@@ -314,7 +325,7 @@ int db_insert_pcontact(struct pcontact* _c)
 		return -1;
 	}
 
-	if (ul_dbf.insert(ul_dbh, keys, values, 13) < 0) {
+	if (ul_dbf.insert(ul_dbh, keys, values, 15) < 0) {
 		LM_ERR("inserting contact in db failed\n");
 		return -1;
 	}

+ 12 - 4
modules/ims_usrloc_pcscf/usrloc_db.h

@@ -12,17 +12,20 @@ typedef enum location_pcscf_fields_idx {
 //	LP_ID_IDX = 0,
 	LP_DOMAIN_IDX = 0,
 	LP_AOR_IDX,
-	LP_CONTACT_IDX,
 	LP_RECEIVED_IDX,
 	LP_RECEIVED_PORT_IDX,
 	LP_RECEIVED_PROTO_IDX,
 	LP_PATH_IDX,
+        LP_RINSTANCE_IDX,
 	LP_RX_SESSION_ID_IDX,
 	LP_REG_STATE_IDX,
 	LP_EXPIRES_IDX,
 	LP_SERVICE_ROUTES_IDX,
 	LP_SOCKET_IDX,
 	LP_PUBLIC_IPS_IDX,
+                LP_HOST_IDX,
+                LP_PORT_IDX,
+                LP_PROTOCOL_IDX
 
 } location_pcscf_fields_idx_t;
 
@@ -52,12 +55,15 @@ typedef enum location_pcscf_fields_idx {
 
 #define ID_COL				"id"
 #define DOMAIN_COL			"domain"
+#define HOST_COL			"host"
+#define PORT_COL			"port"
+#define PROTOCOL_COL		"protocol"
 #define AOR_COL				"aor"
-#define CONTACT_COL			"contact"
 #define RECEIVED_COL		"received"
 #define RECEIVED_PORT_COL	"received_port"
 #define RECEIVED_PROTO_COL	"received_proto"
 #define PATH_COL			"path"
+#define RINSTANCE_COL           "rinstance"
 #define RX_SESSION_ID_COL	"rx_session_id"
 #define REG_STATE_COL		"reg_state"
 #define EXPIRES_COL			"expires"
@@ -65,7 +71,7 @@ typedef enum location_pcscf_fields_idx {
 #define SOCKET_COL			"socket"
 #define PUBLIC_IDS_COL		"public_ids"
 #define SECURITY_TYPE_COL	"security_type"
-#define PROTOCOL_COL		"protocol"
+
 #define MODE_COL			"mode"
 #define CK_COL				"ck"
 #define IK_COL				"ik"
@@ -97,7 +103,9 @@ extern db_func_t ul_dbf;
 extern str id_col;
 extern str domain_col;
 extern str aor_col;
-extern str contact_col;
+extern str host_col;
+extern str port_col;
+extern str protocol_col;
 extern str received_col;
 extern str received_port_col;
 extern str received_proto_col;

+ 184 - 0
modules/ims_usrloc_scscf/contact_dlg_handlers.c

@@ -0,0 +1,184 @@
+/*-------------------------------------------------------------------------------------------------------------------\
+|Version           Date        Author              Description                                                       |
+|--------------------------------------------------------------------------------------------------------------------|
+|Initial Build     20150825   T.Ntamane            Contact dialog handler for expired|terminated|destroyed| etc      |
+\-----------------------------------------------------------------------------------------------------------------TN*/
+
+
+#include "impurecord.h"
+#include "usrloc.h"
+#include "ucontact.h"
+#include "dlist.h"
+#include "../../modules/dialog_ng/dlg_load.h"
+#include "../../modules/dialog_ng/dlg_hash.h"
+
+extern struct dlg_binds dlgb;
+
+/*------------------------------------------------------------------------------------\
+| Our call back handler function that handles |confirmed|expired|terminated|destroy.  |
+\------------------------------------------------------------------------------* V1.1*/
+
+static void contact_dlg_handler(struct dlg_cell* dlg, int cb_types, struct dlg_cb_params *dlg_params);
+
+/*-----------------------------------------------------------------------------------------------------------\
+| Our setup call back handler function primarily for create, that further register for other callback       .|
+\------------------------------------------------------------------------------------------------------V1.1-*/
+void contact_dlg_create_handler(struct dlg_cell* dlg, int cb_types, struct dlg_cb_params *dlg_params) {
+    if (cb_types != DLGCB_CREATED) {
+        LM_ERR("Unknown event type  %d", cb_types);
+        return;
+    }
+    if ((dlgb.register_dlgcb(dlg, DLGCB_CONFIRMED | DLGCB_EXPIRED | DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_FAILED, contact_dlg_handler, 0, 0))
+
+            ) {
+        LM_ERR("Error registering dialog for contact caller id [%.*s] ", dlg->callid.len, dlg->callid.s);
+        return;
+    }
+    LM_DBG("Successfully registered contact dialog handler\n");
+}
+
+/**
+ * Search for a contact related to an IMPU based on an original contact string (uri)
+ * @param impu impurecord we will search through
+ * @param search_aor the raw uri we are using as the source of the search
+ * @return 0 on success, anything else on failure
+ */
+static inline int find_contact_from_impu(impurecord_t* impu, str* search_aor, ucontact_t** scontact) {
+    
+    int iCount = 0;
+    short i_searchlen;
+    char *s_term;
+    
+    if (!search_aor)
+        return 1;
+    
+    LM_DBG("Looking for contact [%.*s] for IMPU [%.*s]\n", search_aor->len, search_aor->s, impu->public_identity.len, impu->public_identity.s);
+    
+    s_term = memchr(search_aor->s,'@',search_aor->len);
+    if (!s_term)
+    {
+        LM_DBG("Malformed contact...bailing search\n"); 
+        return 1;
+    }        
+    i_searchlen = s_term - search_aor->s;
+    for (;iCount < impu->num_contacts ; ++iCount)
+    {                
+        if( impu->newcontacts[iCount] && impu->newcontacts[iCount]->aor.s[i_searchlen] == '@' 
+                                      && (memcmp(impu->newcontacts[iCount]->aor.s, search_aor->s, i_searchlen) == 0))           
+        {
+            *scontact = impu->newcontacts[iCount];  
+            return 0;
+        }        
+        if (impu->newcontacts[iCount])
+           LM_DBG("Skipping %.*s\n",impu->newcontacts[iCount]->aor.len,impu->newcontacts[iCount]->aor.s);
+    }    
+    return 1;
+}
+
+static void contact_dlg_handler(struct dlg_cell* dlg, int cb_types, struct dlg_cb_params *dlg_params) {
+    struct ucontact *ucontact_caller = 0x00,
+            *ucontact_callee = 0x00;
+    udomain_t *_d;
+    impurecord_t* from_impu, *to_impu;
+    str from_uri_clean, to_uri_clean;
+    char *p;
+    short iFoundCaller = 0,
+          iFoundCallee  = 0;
+    static unsigned int i_confirmed_count  = 0,
+                        i_terminated_count =0;
+
+    if ((cb_types == DLGCB_CONFIRMED) ||
+            (cb_types == DLGCB_EXPIRED) ||
+            (cb_types == DLGCB_TERMINATED) ||
+            (cb_types == DLGCB_DESTROY) ||
+            (cb_types == DLGCB_FAILED)) {
+
+        //for now we will abort if there is no dlg_out.... TODO maybe we can only do the caller side....
+        if (dlg->dlg_entry_out.first == 0x00) {
+            LM_ERR("no dlg out... ignoring!!! for type [%d]\n",cb_types);
+            return;
+        }
+        register_udomain("location", &_d);
+        
+        from_uri_clean.s = dlg->from_uri.s;
+        from_uri_clean.len = dlg->from_uri.len;
+        p = memchr(dlg->from_uri.s, ';', dlg->from_uri.len);
+        if (p)
+            from_uri_clean.len = p - from_uri_clean.s;
+        
+        lock_udomain(_d, &from_uri_clean);
+        if (get_impurecord(_d, &from_uri_clean, &from_impu) != 0) {
+            LM_DBG("Could not find caller impu for [%.*s]\n", from_uri_clean.len, from_uri_clean.s);
+            unlock_udomain(_d, &from_uri_clean);
+            return;
+        }
+        
+        if (find_contact_from_impu(from_impu, &dlg->caller_contact, &ucontact_caller) !=0) {
+            LM_DBG("Unable to find caller contact from dialog.... continuing\n");
+            //unlock_udomain(_d, &from_uri_clean);
+            //return;
+        }
+        else {
+           iFoundCaller = 1;
+        }
+        unlock_udomain(_d, &from_uri_clean);
+        
+        to_uri_clean.s = dlg->dlg_entry_out.first->to_uri.s;
+        to_uri_clean.len = dlg->dlg_entry_out.first->to_uri.len;
+        p = memchr(dlg->dlg_entry_out.first->to_uri.s, ';', dlg->dlg_entry_out.first->to_uri.len);
+        if (p)
+            to_uri_clean.len = p - to_uri_clean.s;
+        
+        lock_udomain(_d, &to_uri_clean);
+        if (get_impurecord(_d, &to_uri_clean, &to_impu) != 0) {
+            LM_DBG("Could not find callee impu for [%.*s]\n", to_uri_clean.len, to_uri_clean.s);
+            unlock_udomain(_d, &to_uri_clean);
+            return;
+        }
+        if (find_contact_from_impu(to_impu, &dlg->dlg_entry_out.first->callee_contact, &ucontact_callee) !=0) {
+            LM_DBG("Unable to find callee contact from dialog.... continuing\n");
+            //unlock_udomain(_d, &to_uri_clean);
+            //return;
+        }
+        else{            
+           iFoundCallee = 1;
+        }
+        unlock_udomain(_d, &to_uri_clean);
+        
+    } else {
+        LM_ERR("Unknown event type [%d] for callid [%.*s] ", cb_types, dlg->callid.len, dlg->callid.s);
+        return;
+    }
+    if(!iFoundCaller && !iFoundCallee)
+    {
+        LM_ERR("No Contacts found for both caller && callee ... bailing\n");
+        return;
+    }
+    switch (cb_types) {
+        case DLGCB_CONFIRMED:
+            LM_DBG("Confirmed contact of type [%d] ,caller_id [%.*s] from handler ", cb_types, dlg->callid.len, dlg->callid.s);
+            if (iFoundCaller)
+              add_dialog_data_to_contact(ucontact_caller, dlg->h_entry, dlg->h_id);
+            if(iFoundCallee)
+              add_dialog_data_to_contact(ucontact_callee, dlg->h_entry, dlg->h_id);//dlg->dlg_entry_out.first->h_entry, dlg->dlg_entry_out.first->h_id);
+            i_confirmed_count++;
+            break;
+        case DLGCB_FAILED:
+        case DLGCB_DESTROY:
+        case DLGCB_EXPIRED:
+        case DLGCB_TERMINATED:
+            LM_DBG("Terminated contact of type [%d] , caller_id [%.*s] from handler ", cb_types, dlg->callid.len, dlg->callid.s);
+            if(iFoundCaller)
+               remove_dialog_data_from_contact(ucontact_caller, dlg->h_entry, dlg->h_id);
+            if(iFoundCallee)
+              //if (dlg->dlg_entry_out.first) {
+                remove_dialog_data_from_contact(ucontact_callee, dlg->h_entry, dlg->h_id);//dlg->dlg_entry_out.first->h_entry, dlg->dlg_entry_out.first->h_id);
+            //}
+            i_terminated_count++;
+            break;
+    }
+    if (i_confirmed_count > 100 && !(i_confirmed_count % 100))
+    {
+        LM_ERR("Curent confirmed count %d terminated count %d \n",i_confirmed_count, i_terminated_count);
+    }
+}

+ 1 - 1
modules/ims_usrloc_scscf/dlist.c

@@ -234,7 +234,7 @@ static inline int get_all_mem_ucontacts(void *buf, int len, unsigned int flags,
  * \param part_max maximal part
  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
  */
-int get_all_ucontacts(void *buf, int len, unsigned int flags,
+int get_all_scontacts(void *buf, int len, unsigned int flags,
 								unsigned int part_idx, unsigned int part_max)
 {
 	return get_all_mem_ucontacts( buf, len, flags, part_idx, part_max);

+ 1 - 1
modules/ims_usrloc_scscf/dlist.h

@@ -130,7 +130,7 @@ int synchronize_all_udomains(void);
  * \param part_max maximal part
  * \return 0 on success, positive if buffer size was not sufficient, negative on failure
  */
-int get_all_ucontacts(void *buf, int len, unsigned int flags,
+int get_all_scontacts(void *buf, int len, unsigned int flags,
 		unsigned int part_idx, unsigned int part_max);
 
 

+ 63 - 43
modules/ims_usrloc_scscf/impurecord.c

@@ -219,7 +219,7 @@ void free_impurecord(impurecord_t* _r) {
  */
 void print_impurecord(FILE* _f, impurecord_t* _r) {
     ucontact_t* ptr;
-    int i;
+    int i = 0;
 
     fprintf(_f, "...Record(%p)...\n", _r);
     fprintf(_f, "domain : '%.*s'\n", _r->domain->len, ZSW(_r->domain->s));
@@ -268,7 +268,7 @@ void print_impurecord(FILE* _f, impurecord_t* _r) {
  * \param _ci contact information
  * \return pointer to new created contact on success, 0 on failure
  */
-ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) {
+ucontact_t* mem_insert_scontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci) {
     ucontact_t* c;
     int sl;
 
@@ -308,7 +308,14 @@ void mem_delete_ucontact(ucontact_t* _c) {
 
     struct contact_dialog_data *dialog_data;
     //tear down dialogs in dialog data list
+    LM_DBG("Checking if dialog_data is there and needs to be torn down\n");
+    if(_c->first_dialog_data == 0) {
+        LM_DBG("first dialog is 0!\n");
+    } else {
+        LM_DBG("first dialog is not 0\n");
+    }
     for (dialog_data = _c->first_dialog_data; dialog_data;) {
+        LM_DBG("Going to tear down dialog with info h_entry [%d] h_id [%d]\n", dialog_data->h_entry, dialog_data->h_id);
         dlgb.lookup_terminate_dlg(dialog_data->h_entry, dialog_data->h_id, NULL);
         dialog_data = dialog_data->next;
     }
@@ -316,7 +323,6 @@ void mem_delete_ucontact(ucontact_t* _c) {
     mem_remove_ucontact(_c);
     free_ucontact(_c);
 }
-
 /*!
  * \brief Expires timer for NO_DB db_mode
  *
@@ -374,11 +380,30 @@ static inline void process_impurecord(impurecord_t* _r) {
         if ((ptr = _r->newcontacts[k])) {
             flag = 1;
             if (!VALID_CONTACT(ptr, act_time)) {
-                LM_DBG("IMPU:<%.*s> - contact:<%.*s> has expired... unlinking contact from IMPU\n", _r->public_identity.len, _r->public_identity.s, ptr->c.len, ptr->c.s);
-                contacts_to_expire[num_contacts_to_expire] = ptr;
-                num_contacts_to_expire++;
+                if (ptr->state == CONTACT_DELETED) {
+                    LM_DBG("Contact: <%.*s> has been deleted - unlinking from IMPU\n", ptr->c.len, ptr->c.s);
+                    contacts_to_expire[num_contacts_to_expire] = ptr;
+                    num_contacts_to_expire++;
+                } else if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
+                    LM_DBG("Contact: <%.*s> is in state CONTACT_EXPIRE_PENDING_NOTIFY....running callback\n", ptr->c.len, ptr->c.s);
+                    if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) {
+                        LM_DBG("Running callback UL_IMPU_DELETE_CONTACT for contact [%.*s] and impu [%.*s]\n", ptr->c.len, ptr->c.s, _r->public_identity.len, _r->public_identity.s);
+                        run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, ptr);
+                    }
+                    hascontacts = 1;    // we do this because the impu must only be deleted if in state deleted....
+                    mustdeleteimpu = 0;
+                } else if (ptr->state == CONTACT_VALID) {
+                    LM_DBG("Contact: <%.*s> is in state valid but it has expired.... ignoring as the contact check will set the appropriate action/state\n", ptr->c.len, ptr->c.s);
+                    mustdeleteimpu = 0;
+                    hascontacts = 1;
+                } else {
+                    LM_WARN("Bogus state for contact [%.*s] - state: %d... ignoring", ptr->c.len, ptr->c.s, ptr->state);
+                    mustdeleteimpu = 0;
+                    hascontacts = 1;
+                }
             } else {
-                LM_DBG("\t\tContact #%i - %.*s, Ref [%d] (expires in %ld seconds)\n", k, ptr->c.len, ptr->c.s, ptr->ref_count, ptr->expires - act_time);
+                LM_DBG("\t\tContact #%i - %.*s, Ref [%d] (expires in %ld seconds) (State: %d)\n", 
+                        k, ptr->c.len, ptr->c.s, ptr->ref_count, ptr->expires - act_time, ptr->state);
                 mustdeleteimpu = 0;
                 hascontacts = 1;
             }
@@ -389,7 +414,7 @@ static inline void process_impurecord(impurecord_t* _r) {
     }
 
     if (num_contacts_to_expire > 0) {
-        LM_DBG("\tThere are %d contacts to expire\n", num_contacts_to_expire);
+        LM_DBG("\tThere are %d contacts to expire/unlink\n", num_contacts_to_expire);
         for (n = 0; n < num_contacts_to_expire; n++) {
             ptr = contacts_to_expire[n];
             LM_DBG("\t\texpiring contact %i: [%.*s] in slot [%d]\n", n, contacts_to_expire[n]->c.len, contacts_to_expire[n]->c.s, contacts_to_expire[n]->sl);
@@ -441,7 +466,7 @@ int get_contacts_count(impurecord_t* _r) {
  * \param _c new created contact
  * \return 0 on success, -1 on failure
  */
-int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c) {
+int insert_scontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c) {
     //First check our constraints
     if (maxcontact > 0 && maxcontact_behaviour > 0) {
         int numcontacts = get_contacts_count(_r);
@@ -453,7 +478,7 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
                 case 2://overwrite oldest
                     LM_DBG("Too many contacts already registered, overwriting oldest for IMPU <%.*s>\n", _r->public_identity.len, _r->public_identity.s);
                     //we can just remove the first one seeing the contacts are ordered on insertion with newest last and oldest first
-                    delete_ucontact(_r->newcontacts[0]);
+                    //TODO:mem_delete_ucontact(_r, _r->contacts);
                     break;
                 default://unknown
                     LM_ERR("unknown maxcontact behaviour..... ignoring\n");
@@ -464,7 +489,7 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
 
     //at this stage we are safe to insert the new contact
     LM_DBG("INSERTing ucontact in usrloc module\n");
-    if (((*_c) = mem_insert_ucontact(_r, _contact, _ci)) == 0) {
+    if (((*_c) = mem_insert_scontact(_r, _contact, _ci)) == 0) {
         LM_ERR("failed to insert contact\n");
         return -1;
     }
@@ -477,8 +502,8 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
 
     //make sure IMPU is linked to this contact
     link_contact_to_impu(_r, *_c, 1);
-    
-    release_ucontact(*_c);
+
+    release_scontact(*_c);
 
     if (exists_ulcb_type(NULL, UL_CONTACT_INSERT)) {
         run_ul_callbacks(NULL, UL_CONTACT_INSERT, _r, *_c);
@@ -489,13 +514,14 @@ int insert_ucontact(impurecord_t* _r, str* _contact, ucontact_info_t* _ci, ucont
 
     return 0;
 }
+
 /*!
  * \brief Delete ucontact from impurecord
  * \param _r record where the contact belongs to
  * \param _c deleted contact
  * \return 0 on success, -1 on failure
  */
-int delete_ucontact(struct ucontact* _c) {
+int delete_scontact(struct ucontact* _c) {
     int ret = 0;
 
     LM_DBG("Deleting contact: [%.*s]\n", _c->c.len, _c->c.s);
@@ -586,7 +612,7 @@ static inline struct ucontact* contact_port_ip_match(unsigned int slot, str* _c)
 static inline struct ucontact* contact_callid_match(unsigned int slot,
         str* _c, str *_callid) {
     ucontact_t* ptr = contact_list->slot[slot].first;
-    
+
     while (ptr) {
         if ((_c->len == ptr->c.len) && (_callid->len == ptr->callid.len)
                 && !memcmp(_c->s, ptr->c.s, _c->len)
@@ -636,7 +662,7 @@ static inline struct ucontact* contact_path_match(unsigned int slot, str* _c, st
  * \return 0 - found, 1 - not found, -1 - invalid found,
  * -2 - found, but to be skipped (same cseq) - don't forget to release_ucontact so dec. the ref counter
  */
-int get_ucontact(impurecord_t* _r, str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co) {
+int get_scontact(str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co) {
     unsigned int sl;
     ucontact_t* ptr;
     int with_callid = 0;
@@ -677,9 +703,9 @@ int get_ucontact(impurecord_t* _r, str* _c, str* _callid, str* _path, int _cseq,
             if (_cseq < ptr->cseq) {
                 LM_DBG("cseq less than expected\n");
             }
-            
+
         }
-        LM_DBG("contact found p=[%p], aor:[%.*s] and contact:[%.*s]\n", ptr, ptr->aor.len, ptr->aor.s, ptr->c.len, ptr->c.s);
+        LM_DBG("contact found p=[%p], aor:[%.*s] and contact:[%.*s], state [%d]\n", ptr, ptr->aor.len, ptr->aor.s, ptr->c.len, ptr->c.s, ptr->state);
         ref_contact_unsafe(ptr);
         *_co = ptr;
         unlock_contact_slot_i(sl); /*TODO: we probably need to ref count here..... */
@@ -781,21 +807,21 @@ int compare_subscription(ims_subscription* new, ims_subscription* orig) {
             for (k = 0; k < new->service_profiles_cnt; k++) {
                 for (l = 0; l < new->service_profiles[k].public_identities_cnt; l++) {
                     LM_DBG("new %.*s (%i) vs. orig %.*s (%i)\n",
-                      new->service_profiles[k].public_identities[l].public_identity.len,
-                      new->service_profiles[k].public_identities[l].public_identity.s,
-                      new->service_profiles[k].public_identities[l].public_identity.len,
-                      orig->service_profiles[i].public_identities[j].public_identity.len,
-                      orig->service_profiles[i].public_identities[j].public_identity.s,
-                      orig->service_profiles[i].public_identities[j].public_identity.len);
-
-                    if (orig->service_profiles[i].public_identities[j].public_identity.len == 
-                      new->service_profiles[k].public_identities[l].public_identity.len) {
+                            new->service_profiles[k].public_identities[l].public_identity.len,
+                            new->service_profiles[k].public_identities[l].public_identity.s,
+                            new->service_profiles[k].public_identities[l].public_identity.len,
+                            orig->service_profiles[i].public_identities[j].public_identity.len,
+                            orig->service_profiles[i].public_identities[j].public_identity.s,
+                            orig->service_profiles[i].public_identities[j].public_identity.len);
+
+                    if (orig->service_profiles[i].public_identities[j].public_identity.len ==
+                            new->service_profiles[k].public_identities[l].public_identity.len) {
                         if (memcmp(orig->service_profiles[i].public_identities[j].public_identity.s,
-                          new->service_profiles[k].public_identities[l].public_identity.s,
-                          new->service_profiles[k].public_identities[l].public_identity.len) == 0)
+                                new->service_profiles[k].public_identities[l].public_identity.s,
+                                new->service_profiles[k].public_identities[l].public_identity.len) == 0)
                             return 1;
                     }
-                    
+
                 }
             }
         }
@@ -853,7 +879,7 @@ int update_impurecord(struct udomain* _d, str* public_identity, impurecord_t* im
                 ref_subscription_unsafe(subs_ptr); //we reference coz we are using it - will be unreferenced later.
                 add_subscription_unsafe(subs_ptr);
                 unlock_subscription_slot(subs_ptr->sl);
-            }            
+            }
         }
         lock_subscription(subs_ptr);
         subscription_locked = 1;
@@ -1050,15 +1076,6 @@ int unlink_contact_from_impu(impurecord_t* impu, ucontact_t* contact, int write_
             LM_DBG("zero'ing last pointer to contact in the list\n");
             impu->newcontacts[i - 1] = 0;
         }
-        LM_DBG("unlinking contact [%.*s] from impu [%.*s]\n", found_contact->c.len, found_contact->c.s, impu->public_identity.len, impu->public_identity.s);
-        if (is_explicit && exists_ulcb_type(impu->cbs, UL_IMPU_DELETE_CONTACT)) {
-            LM_DBG("Running callback UL_IMPU_DELETE_CONTACT for contact [%.*s] and impu [%.*s]\n", found_contact->c.len, found_contact->c.s, impu->public_identity.len, impu->public_identity.s);
-            run_ul_callbacks(impu->cbs, UL_IMPU_DELETE_CONTACT, impu, found_contact);
-        }
-        if (!is_explicit && exists_ulcb_type(impu->cbs, UL_IMPU_DELETE_CONTACT_IMPLICIT)) {
-            LM_DBG("Running callback UL_IMPU_DELETE_CONTACT_IMPLICIT for contact [%.*s] and impu [%.*s]\n", found_contact->c.len, found_contact->c.s, impu->public_identity.len, impu->public_identity.s);
-            run_ul_callbacks(impu->cbs, UL_IMPU_DELETE_CONTACT_IMPLICIT, impu, found_contact);
-        }
 
         if (write_to_db && db_mode == WRITE_THROUGH && db_unlink_contact_from_impu(impu, found_contact) != 0) {
             LM_ERR("Failed to un-link DB contact [%.*s] from IMPU [%.*s]...continuing but db will be out of sync!\n", found_contact->c.len, found_contact->c.s, impu->public_identity.len, impu->public_identity.s);
@@ -1085,12 +1102,15 @@ void unref_subscription_unsafe(ims_subscription* s) {
 
     LM_DBG("un-reffing subscription [%.*s] - was [%d]\n", s->private_identity.len, s->private_identity.s, s->ref_count);
     s->ref_count--;
-    if (s->ref_count == 0 && (s->sl >= 0)) { //-1 as sl means the subscription was never added to the list
-        sl = s->sl;
-        subs_slot_rem(&ims_subscription_list->slot[sl], s);
+    if (s->ref_count == 0) {
+        if (s->sl >= 0) { //-1 as sl means the subscription was never added to the list
+            sl = s->sl;
+            subs_slot_rem(&ims_subscription_list->slot[sl], s);
+        }
         delete_subscription(s);
         s = 0;
     }
+    
 }
 
 void ref_subscription(ims_subscription* s) {

+ 4 - 4
modules/ims_usrloc_scscf/impurecord.h

@@ -97,7 +97,7 @@ void print_impurecord(FILE* _f, impurecord_t* _r);
  * \param _ci contact information
  * \return pointer to new created contact on success, 0 on failure
  */
-ucontact_t* mem_insert_ucontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci);
+ucontact_t* mem_insert_scontact(impurecord_t* _r, str* _c, ucontact_info_t* _ci);
 
 
 /*!
@@ -142,7 +142,7 @@ void free_ims_subscription_data(ims_subscription *s);
  * \param _c new created contact
  * \return 0 on success, -1 on failure
  */
-int insert_ucontact(impurecord_t* _r, str* _contact,
+int insert_scontact(impurecord_t* _r, str* _contact,
 		ucontact_info_t* _ci, ucontact_t** _c);
 
 
@@ -152,7 +152,7 @@ int insert_ucontact(impurecord_t* _r, str* _contact,
  * \param _c deleted contact
  * \return 0 on success, -1 on failure
  */
-int delete_ucontact(struct ucontact* _c);
+int delete_scontact(struct ucontact* _c);
 
 
 /*!
@@ -166,7 +166,7 @@ int delete_ucontact(struct ucontact* _c);
  * \return 0 - found, 1 - not found, -1 - invalid found, 
  * -2 - found, but to be skipped (same cseq)
  */
-int get_ucontact(impurecord_t* _r, str* _c, str* _callid, str* _path,
+int get_scontact(str* _c, str* _callid, str* _path,
 		int _cseq,
 		struct ucontact** _co);
 

+ 9 - 8
modules/ims_usrloc_scscf/ucontact.c

@@ -396,7 +396,7 @@ static inline void update_contact_pos(struct impurecord* _r, ucontact_t* _c) {
  * \param _c updated contact
  * \return 0 on success, -1 on failure
  */
-int expire_ucontact(struct impurecord* _r, ucontact_t* _c) {
+int expire_scontact(struct impurecord* _r, ucontact_t* _c) {
     /* we have to update memory in any case, but database directly
      * only in db_mode 1 */
     LM_DBG("Expiring contact aor: [%.*s] and contact uri: [%.*s]\n", _c->aor.len, _c->aor.s, _c->c.len, _c->c.s);
@@ -434,7 +434,7 @@ int expire_ucontact(struct impurecord* _r, ucontact_t* _c) {
  * \param _ci new contact informations
  * \return 0 on success, -1 on failure
  */
-int update_ucontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci) {
+int update_scontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci) {
     /* we have to update memory in any case, but database directly
      * only in db_mode 1 */
     LM_DBG("Updating contact aor: [%.*s] and contact uri: [%.*s]\n", _c->aor.len, _c->aor.s, _c->c.len, _c->c.s);
@@ -503,7 +503,7 @@ int add_dialog_data_to_contact(ucontact_t* _c, unsigned int h_entry, unsigned in
  * used when this contact is part of a confirmed dialog so we can tear down the dialog if the contact is removed
  */
 int remove_dialog_data_from_contact(ucontact_t* _c, unsigned int h_entry, unsigned int h_id) {
-    struct contact_dialog_data *dialog_data, *tmp_dialog_data; 
+    struct contact_dialog_data *dialog_data, *tmp_dialog_data;     
     LM_DBG("Removing dialog data from contact <%.*s> with h_entry <%d> and h_id <%d>", _c->c.len, _c->c.s, h_entry, h_id);
     
     for (dialog_data = _c->first_dialog_data; dialog_data;) {
@@ -521,16 +521,17 @@ int remove_dialog_data_from_contact(ucontact_t* _c, unsigned int h_entry, unsign
 	    }else{
 	       _c->last_dialog_data =  tmp_dialog_data->prev;
 	    }
-	    shm_free(tmp_dialog_data);
-	    return 0;
+	    shm_free(tmp_dialog_data);            
+	    return 0; 
 	}
         
     }
-    LM_DBG("Did not find dialog data to remove from contact");
-    return 0;
+   
+      LM_DBG("Did not find dialog data to remove from contact");
+      return 1;              
 }
 
-void release_ucontact(struct ucontact* _c) {
+void release_scontact(struct ucontact* _c) {
     lock_contact_slot_i(_c->sl);
     unref_contact_unsafe(_c);
     unlock_contact_slot_i(_c->sl);

+ 3 - 3
modules/ims_usrloc_scscf/ucontact.h

@@ -105,7 +105,7 @@ int mem_update_ucontact(ucontact_t* _c, ucontact_info_t *_ci);
  * \param _ci new contact informations
  * \return 0 on success, -1 on failure
  */
-int update_ucontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci);
+int update_scontact(struct impurecord* _r, ucontact_t* _c, ucontact_info_t* _ci);
 
 /*!
  * \brief Setting contact expires to now in memory
@@ -120,12 +120,12 @@ int mem_expire_ucontact(ucontact_t* _c);
  * \param _c updated contact
  * \return 0 on success, -1 on failure
  */
-int expire_ucontact(struct impurecord* _r, ucontact_t* _c);
+int expire_scontact(struct impurecord* _r, ucontact_t* _c);
 
 int remove_dialog_data_from_contact(ucontact_t* _c, unsigned int h_entry, unsigned int h_id);
 
 int add_dialog_data_to_contact(ucontact_t* _c, unsigned int h_entry, unsigned int h_id);
 
-void release_ucontact(struct ucontact* _c);
+void release_scontact(struct ucontact* _c);
 
 #endif

+ 43 - 3
modules/ims_usrloc_scscf/udomain.c

@@ -249,6 +249,10 @@ void mem_delete_impurecord(udomain_t* _d, struct impurecord* _r) {
     counter_add(ul_scscf_cnts_h.active_impus, -1);
 }
 
+static unsigned int expired_contacts_size = 0;
+ucontact_t** expired_contacts = 0;
+
+
 /*!
  * \brief Run timer handler for given domain
  * \param _d domain
@@ -256,8 +260,25 @@ void mem_delete_impurecord(udomain_t* _d, struct impurecord* _r) {
 void mem_timer_udomain(udomain_t* _d) {
     struct impurecord* ptr, *t;
     struct ucontact* contact_ptr;
+    unsigned int num_expired_contacts = 0;
     int i, n, temp;
-
+    time_t now;
+    
+    now = time(0);
+    int numcontacts = contact_list->max_collisions?(contact_list->max_collisions * contact_list->size):(contact_list->size);
+    if (expired_contacts_size < numcontacts) {
+        LM_DBG("Changing expired_contacts list size from %d to %d\n", expired_contacts_size, numcontacts);
+        if (expired_contacts){
+            pkg_free(expired_contacts);
+        }
+        expired_contacts = (ucontact_t**)pkg_malloc(numcontacts*sizeof(ucontact_t**));
+        if (!expired_contacts) {
+            LM_ERR("no more pkg mem\n");
+            return;
+        }
+        expired_contacts_size = numcontacts;
+    }
+    
     //go through contacts first
     n = contact_list->max_collisions;
     LM_DBG("*** mem_timer_udomain - checking contacts - START ***\n");
@@ -265,8 +286,18 @@ void mem_timer_udomain(udomain_t* _d) {
         lock_contact_slot_i(i);
         contact_ptr = contact_list->slot[i].first;
         while (contact_ptr) {
-            LM_DBG("We have a contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d\n", i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, (double) contact_ptr->expires - time(NULL), contact_ptr->ref_count);
+            LM_DBG("We have a contact in the new contact list in slot %d = [%.*s] (%.*s) which expires in %lf seconds and has a ref count of %d (state: %d)\n", 
+                    i, contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s, 
+                    (double) contact_ptr->expires - now, contact_ptr->ref_count,
+                    contact_ptr->state);
 		//contacts are now deleted during impurecord processing
+            if ((contact_ptr->expires-now) <=0 && (contact_ptr->state != CONTACT_DELETED)) {
+                LM_DBG("expiring contact [%.*s].... setting to CONTACT_EXPIRE_PENDING_NOTIFY\n", contact_ptr->aor.len, contact_ptr->aor.s);
+                contact_ptr->state = CONTACT_EXPIRE_PENDING_NOTIFY;
+                ref_contact_unsafe(contact_ptr);
+                expired_contacts[num_expired_contacts] = contact_ptr;
+                num_expired_contacts++;
+            }
             contact_ptr = contact_ptr->next;
         } 
         if (contact_list->slot[i].n > n) {
@@ -317,6 +348,15 @@ void mem_timer_udomain(udomain_t* _d) {
     }
     ims_subscription_list->max_collisions = n;
     
+    /* now we delete the expired contacts.  (mark them for deletion */
+    for (i=0; i<num_expired_contacts; i++) {
+        lock_contact_slot_i(expired_contacts[i]->sl);
+        LM_DBG("Setting contact state to CONTACT_DELETED for contact [%.*s]\n", expired_contacts[i]->aor.len, expired_contacts[i]->aor.s);
+        expired_contacts[i]->state = CONTACT_DELETED;
+        unref_contact_unsafe(expired_contacts[i]);
+        unlock_contact_slot_i(expired_contacts[i]->sl);
+    }
+    
 }
 
 
@@ -756,6 +796,6 @@ void unref_contact_unsafe(ucontact_t* c) {
         if (c->ref_count < 0) {
             LM_WARN("reference dropped below zero... this should not happen\n");
         }
-        delete_ucontact(c);
+        delete_scontact(c);
     }
 }

+ 15 - 1
modules/ims_usrloc_scscf/ul_mod.c

@@ -79,6 +79,7 @@ static void timer(unsigned int ticks, void* param); /*!< Timer handler */
 static int child_init(int rank);                    /*!< Per-child init function */
 
 extern int bind_usrloc(usrloc_api_t* api);
+extern void contact_dlg_create_handler(struct dlg_cell* dlg, int cb_types, struct dlg_cb_params *dlg_params);/*V1.1*/
 extern int ul_locks_no;
 extern int subs_locks_no;
 extern int contacts_locks_no;
@@ -374,7 +375,20 @@ static int mod_init(void) {
 	}
 
 	init_flag = 1;
-	
+        
+	/* From contact_dlg_handlers.c
+         * 
+         * V1.1*/
+         
+        if (dlgb.register_dlgcb(0x00, DLGCB_CREATED, contact_dlg_create_handler, 0x00, 0x00) )
+        {
+            LM_ERR("Unable to setup DLGCB_CREATED");
+            return -1;
+        }
+        else
+        {
+            LM_DBG(" DLGCB_CREATED created successfully");
+        }
 	return 0;
 }
 

+ 7 - 7
modules/ims_usrloc_scscf/usrloc.c

@@ -94,13 +94,13 @@ int bind_usrloc(usrloc_api_t* api) {
         api->ref_subscription = ref_subscription;
         api->unref_subscription = unref_subscription;
 
-	api->get_all_ucontacts = get_all_ucontacts;
-	api->insert_ucontact = insert_ucontact;
-	api->delete_ucontact = delete_ucontact;
-	api->get_ucontact = get_ucontact;
-	api->release_ucontact = release_ucontact;
-	api->update_ucontact = update_ucontact;
-	api->expire_ucontact = expire_ucontact;
+	api->get_all_ucontacts = get_all_scontacts;
+	api->insert_ucontact = insert_scontact;
+	api->delete_ucontact = delete_scontact;
+	api->get_ucontact = get_scontact;
+	api->release_ucontact = release_scontact;
+	api->update_ucontact = update_scontact;
+	api->expire_ucontact = expire_scontact;
 
 	api->add_dialog_data_to_contact = add_dialog_data_to_contact;
 	api->remove_dialog_data_from_contact = remove_dialog_data_from_contact;

+ 4 - 3
modules/ims_usrloc_scscf/usrloc.h

@@ -143,12 +143,13 @@ typedef enum cstate {
 
 typedef enum contact_state {
     CONTACT_VALID,
-    CONTACT_EXPIRED,
+    CONTACT_DELETE_PENDING,
+    CONTACT_EXPIRE_PENDING_NOTIFY,
     CONTACT_DELETED
 } contact_state_t;
 
 /*! \brief Valid contact is a contact that either didn't expire yet or is permanent */
-#define VALID_CONTACT(c, t)   ((c->expires>t) || (c->expires==0))
+#define VALID_CONTACT(c, t)   (((c->expires>t) || (c->expires==0)) && c->state!=CONTACT_DELETED && c->state!=CONTACT_DELETE_PENDING && c->state!=CONTACT_EXPIRE_PENDING_NOTIFY)
 
 struct hslot;
 /*!< Hash table slot */
@@ -467,7 +468,7 @@ typedef int (*insert_ucontact_t)(struct impurecord* _r, str* _contact, struct uc
 
 typedef int (*delete_ucontact_t)(struct ucontact* _c);
 
-typedef int (*get_ucontact_t)(struct impurecord* _r, str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co);
+typedef int (*get_ucontact_t)(str* _c, str* _callid, str* _path, int _cseq, struct ucontact** _co);
 
 typedef void (*release_ucontact_t)(struct ucontact* _c);
 

+ 5 - 3
modules/ims_usrloc_scscf/usrloc_db.c

@@ -790,6 +790,8 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 			!= 0) {
 		    LM_ERR("Unable to insert IMPU into memory [%.*s]\n", impu.len, impu.s);
 		}
+                /* run the INSERTion callback so REGISTRAR can get into sync - ie subscribe for callbacks on the IMPU.... for NOTIFYs for example*/
+                run_ul_callbacks(NULL, UL_IMPU_INSERT, impurecord, NULL);
 	    }
 
 	    /* add contacts */
@@ -844,9 +846,9 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 				continue;
 			    }
 
-			    if (get_ucontact(impurecord, &contact, contact_data.callid, contact_data.path, contact_data.cseq, &c) != 0) {
+			    if (get_scontact(&contact, contact_data.callid, contact_data.path, contact_data.cseq, &c) != 0) {
 				LM_DBG("Contact doesn't exist yet, creating new one [%.*s]\n", contact.len, contact.s);
-				if ((c = mem_insert_ucontact(impurecord, &contact, &contact_data)) == 0) {
+				if ((c = mem_insert_scontact(impurecord, &contact, &contact_data)) == 0) {
 				    LM_ERR("Unable to insert contact [%.*s] for IMPU [%.*s] into memory... continuing...\n",
 					    contact.len, contact.s,
 					    impu.len, impu.s);
@@ -854,7 +856,7 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 				}
 			    }
 			    link_contact_to_impu(impurecord, c, 0);
-			    release_ucontact(c);
+			    release_scontact(c);
 			}
 			if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
 			    if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {

部分文件因为文件数量过多而无法显示