Просмотр исходного кода

modules/ims_usrloc_scscf: Added database support for subscriptions

Richard Good 11 лет назад
Родитель
Сommit
483baa2615

+ 52 - 28
modules/ims_usrloc_scscf/subscribe.c

@@ -55,11 +55,14 @@
 #include "../../hashes.h"
 
 #include "ul_mod.h"
+#include "usrloc_db.h"
 
 
 extern int sub_dialog_hash_size;
 extern shtable_t sub_dialog_table;
 
+extern int db_mode;
+
 int get_subscriber(impurecord_t* urec, str *presentity_uri, str *watcher_contact, int event, reg_subscriber** r_subscriber) {
     
     reg_subscriber* s = NULL;
@@ -95,7 +98,7 @@ int get_subscriber(impurecord_t* urec, str *presentity_uri, str *watcher_contact
     return 1;
 }
 
-reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri, str* watcher_contact, subscriber_data_t* subscriber_data) {
+reg_subscriber* new_subscriber(subscriber_data_t* subscriber_data) {
     subs_t subs;
     reg_subscriber *s;
 
@@ -107,7 +110,7 @@ reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri, str* watch
     
     len = sizeof (reg_subscriber) + subscriber_data->callid->len
             + subscriber_data->ftag->len + subscriber_data->ttag->len
-            + watcher_contact->len + watcher_uri->len + presentity_uri->len
+            + subscriber_data->watcher_contact->len + subscriber_data->watcher_uri->len + subscriber_data->presentity_uri->len
             + subscriber_data->record_route->len + subscriber_data->sockinfo_str->len;
 
     LM_DBG("Creating new subscription to reg");
@@ -124,6 +127,8 @@ reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri, str* watch
     s->event = subscriber_data->event;
 
     s->expires = subscriber_data->expires;
+    
+    s->version = subscriber_data->version;
 
     p = (char*) (s + 1);
 
@@ -143,14 +148,14 @@ reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri, str* watch
     p += subscriber_data->ftag->len;
 
     s->watcher_uri.s = p;
-    s->watcher_uri.len = watcher_uri->len;
-    memcpy(p, watcher_uri->s, watcher_uri->len);
-    p += watcher_uri->len;
+    s->watcher_uri.len = subscriber_data->watcher_uri->len;
+    memcpy(p, subscriber_data->watcher_uri->s, subscriber_data->watcher_uri->len);
+    p += subscriber_data->watcher_uri->len;
 
     s->watcher_contact.s = p;
-    s->watcher_contact.len = watcher_contact->len;
-    memcpy(p, watcher_contact->s, watcher_contact->len);
-    p += watcher_contact->len;
+    s->watcher_contact.len = subscriber_data->watcher_contact->len;
+    memcpy(p, subscriber_data->watcher_contact->s, subscriber_data->watcher_contact->len);
+    p += subscriber_data->watcher_contact->len;
 
     s->record_route.s = p;
     s->record_route.len = subscriber_data->record_route->len;
@@ -163,9 +168,9 @@ reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri, str* watch
     p += subscriber_data->sockinfo_str->len;
 
     s->presentity_uri.s = p;
-    s->presentity_uri.len = presentity_uri->len;
-    memcpy(p, presentity_uri->s, presentity_uri->len);
-    p += presentity_uri->len;
+    s->presentity_uri.len = subscriber_data->presentity_uri->len;
+    memcpy(p, subscriber_data->presentity_uri->s, subscriber_data->presentity_uri->len);
+    p += subscriber_data->presentity_uri->len;
 
     if (p != (((char*) s) + len)) {
         LM_CRIT("buffer overflow\n");
@@ -231,9 +236,9 @@ str get_presentity_from_subscriber_dialog(str *callid, str *to_tag, str *from_ta
     return pres_uri;
 }
 
+/*db_load:  if this is a db_load then we don't write to db - as it will be an unecessary rewrite*/
 int add_subscriber(impurecord_t* urec,
-        str *watcher_uri, str *watcher_contact,
-        subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber) {
+        subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber, int db_load) {
 
     LM_DBG("Adding reg subscription to IMPU record");
 
@@ -241,9 +246,9 @@ int add_subscriber(impurecord_t* urec,
         LM_ERR("no presentity impu record provided\n");
         return 0;
     }
-    reg_subscriber *s = new_subscriber(&urec->public_identity, watcher_uri, watcher_contact, subscriber_data);
+    reg_subscriber *s = new_subscriber(subscriber_data);
 
-    if (!s) return 1;
+    if (!s) return -1;
 
     LM_DBG("Adding new subscription to IMPU record list");
     s->next = 0;
@@ -253,23 +258,42 @@ int add_subscriber(impurecord_t* urec,
     if (!urec->shead) urec->shead = s;
 
     *_reg_subscriber = s;
+    
+    /*DB?*/
+    if (!db_load && db_mode == WRITE_THROUGH && db_insert_subscriber(urec, s) != 0) {
+	    LM_ERR("error inserting subscriber into db");
+	    return -1;
+    }
     return 0;
 }
 
 
-int update_subscriber(impurecord_t* urec,
-        str *watcher_uri, str *watcher_contact,
-        int *expires, reg_subscriber** _reg_subscriber) {
-
+int update_subscriber(impurecord_t* urec, reg_subscriber** _reg_subscriber, int *expires, int *local_cseq, int *version) {
 
     reg_subscriber *rs = *_reg_subscriber;
     if (expires) {
         rs->expires = *expires;
-        return 1;
     } else {
-        LM_ERR("Failed to update subscriber as expires is expires is null");
-        return 0;
+        LM_DBG("No expires so will not update subscriber expires.\n");
+    }
+    if (local_cseq) {
+        rs->local_cseq = *local_cseq;
+    } else {
+        LM_DBG("No local cseq so will not update subscriber local cseq.\n");
+    }
+    if (version) {
+        rs->version = *version;
+    } else {
+        LM_DBG("No version so will not update subscriber version.\n");
+    }
+    
+    /*DB?*/
+    if (db_mode == WRITE_THROUGH && db_insert_subscriber(urec, rs) != 0) {
+	    LM_ERR("error updating subscriber in db");
+	    return -1;
     }
+    
+    return 1;
 }
 
 
@@ -286,12 +310,7 @@ void external_delete_subscriber(reg_subscriber *s, udomain_t* _t, int lock_domai
         return;
     }
 
-    if (urec->shead == s) urec->shead = s->next;
-    else s->prev->next = s->next;
-    if (urec->stail == s) urec->stail = s->prev;
-    else s->next->prev = s->prev;
-    LM_DBG("About to free subscriber memory");
-    free_subscriber(s);
+    delete_subscriber(urec, s);
 
     if(lock_domain) unlock_udomain(_t, &s->presentity_uri);
 
@@ -299,6 +318,11 @@ void external_delete_subscriber(reg_subscriber *s, udomain_t* _t, int lock_domai
 
 void delete_subscriber(impurecord_t* urec, reg_subscriber *s) {
     LM_DBG("Deleting subscriber");
+    
+    if (db_mode == WRITE_THROUGH && db_delete_subscriber(urec, s) != 0) {
+	    LM_ERR("error removing subscriber from DB [%.*s]... will still remove from memory\n", s->presentity_uri.len, s->presentity_uri.s);
+    }
+    
     if (urec->shead == s) urec->shead = s->next;
     else s->prev->next = s->next;
     if (urec->stail == s) urec->stail = s->prev;

+ 3 - 11
modules/ims_usrloc_scscf/subscribe.h

@@ -48,24 +48,16 @@
 
 #include "usrloc.h"
 
-reg_subscriber* new_subscriber(str* presentity_uri, str* watcher_uri,
-		str* watcher_contact, subscriber_data_t* subscriber_data);
+reg_subscriber* new_subscriber(subscriber_data_t* subscriber_data);
 
 //API declarations
 int get_subscriber(impurecord_t* urec, str *watcher_uri,
 		str *watcher_contact, int event, reg_subscriber** r_subscriber);
 
-int add_subscriber(impurecord_t* urec, str *watcher_uri,
-		str *watcher_contact, subscriber_data_t* subscriber_data,
-		reg_subscriber** _reg_subscriber);
-
-
-int update_subscriber(impurecord_t* urec,
-        str *watcher_uri, str *watcher_contact,
-        int *expires, reg_subscriber** _reg_subscriber);
-
+int add_subscriber(impurecord_t* urec, subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber, int db_load);
 
 
+int update_subscriber(impurecord_t* urec, reg_subscriber** _reg_subscriber, int *expires, int *local_cseq, int *version);
 
 void delete_subscriber(impurecord_t* urec, reg_subscriber *s);
 

+ 1 - 0
modules/ims_usrloc_scscf/ul_mod.c

@@ -227,6 +227,7 @@ static int mod_init(void) {
 		case CONTACT_ONLY:
 		case CONTACT_CALLID:
 		case CONTACT_PATH:
+		case CONTACT_PORT_IP_ONLY:
 			break;
 		default:
 			LM_ERR("invalid matching mode %d\n", matching_mode);

+ 8 - 13
modules/ims_usrloc_scscf/usrloc.h

@@ -99,16 +99,20 @@ typedef struct udomain udomain_t;
 typedef struct _subscriber_data {
 	int event;
 	int expires;
+	int version;
 	str* callid;
 	str* ftag;
 	str* ttag;
 	unsigned int local_cseq;
 	str* record_route;
 	str* sockinfo_str;
+	str* presentity_uri;
+	str *watcher_uri;
+	str* watcher_contact;
 } subscriber_data_t;
 
 typedef struct _reg_subscriber {
-    char event;
+    int event;
     time_t expires; /**< Time of expiration		 			*/
     int version; /**< Last version sent to this subs.	*/
 
@@ -418,24 +422,15 @@ typedef int (*get_all_ucontacts_t)(void* buf, int len, unsigned int flags, unsig
 
 typedef int (*get_udomain_t)(const char* _n, udomain_t** _d);
 
-//typedef int (*update_subscriber_t)(udomain_t* _d, int event,int* expires, str *callid, str *ftag, str *ttag, unsigned int local_cseq, str *watcher_uri, str *watcher_contact, str *presentity_uri, str *record_route, str *sockinfo_str, reg_subscriber** reg_subscriber );
-
-typedef int (*update_subscriber_t)(impurecord_t* urec,
-        str *watcher_uri, str *watcher_contact,
-        int *expires, reg_subscriber** _reg_subscriber);
+typedef int (*update_subscriber_t)(impurecord_t* urec, reg_subscriber** _reg_subscriber,
+        int *expires, int *local_cseq, int *version);
 
 typedef void (*external_delete_subscriber_t)(reg_subscriber *s, udomain_t* _t, int lock_domain);
 
-//typedef int (*get_subscriber_t)(udomain_t* _d, impurecord_t* urec, str *watcher_contact, str *presentity_uri, int event, reg_subscriber** reg_subscriber);
 typedef int (*get_subscriber_t)(impurecord_t* urec, str *watcher_contact, str *presentity_uri, int event, reg_subscriber** reg_subscriber);
 
-//typedef int (*add_subscriber_t)(udomain_t* _d, impurecord_t* urec,
-//		str *watcher_uri, str *watcher_contact,
-//		subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber);
-
 typedef int (*add_subscriber_t)(impurecord_t* urec,
-		str *watcher_uri, str *watcher_contact,
-		subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber);
+		subscriber_data_t* subscriber_data, reg_subscriber** _reg_subscriber, int db_load);
 
 typedef int (*get_impus_from_subscription_as_string_t)(udomain_t* _d, impurecord_t* impu_rec, int barring, str** impus, int* num_impus);
 

+ 553 - 43
modules/ims_usrloc_scscf/usrloc_db.c

@@ -4,6 +4,7 @@
 #include "bin_utils.h"
 #include "udomain.h"
 #include "math.h"
+#include "subscribe.h"
 
 str id_col = str_init(ID_COL); /*!< Name of column containing ID (gen. auto_increment field */
 str impu_id_col = str_init(IMPU_ID_COL); /*!< Name of column containing impu ID in mapping table */
@@ -30,12 +31,38 @@ str sock_col = str_init(SOCK_COL); /*!< Name of column containing the received s
 str methods_col = str_init(METHODS_COL); /*!< Name of column containing the supported methods */
 str last_mod_col = str_init(LAST_MOD_COL); /*!< Name of column containing the last modified date */
 
-str id_column 			= { "id", 2 };
-str impu_table 			= { "impu", 4 };
-str contact_table 		= { "contact", 7 };
-str impu_contact_table 	= { "impu_contact", 12 };
+/*impu table*/
+str impu_table = str_init(IMPU_TABLE);
+
+/*contact table*/
+str contact_table = str_init(CONTACT_TABLE);
+
+/*impu contact table*/
+str impu_contact_table = str_init(IMPU_CONTACT_TABLE);
+
+/*subscriber table*/
+str subscriber_table = str_init(SUBSCRIBER_TABLE);
+str sub_event_col = str_init(SUB_EVENT_COL);
+str sub_expires_col = str_init(SUB_EXPIRES_COL);
+str sub_version_col = str_init(SUB_VERSION_COL);
+str sub_watcher_uri_col = str_init(SUB_WATCHER_URI_COL);
+str sub_watcher_contact_col = str_init(SUB_WATCHER_CONTACT_COL);
+str sub_presentity_uri_col = str_init(SUB_PRESENTITY_URI_COL);
+str sub_local_cseq_col = str_init(SUB_LOCAL_CSEQ_COL);
+str sub_call_id_col = str_init(SUB_CALL_ID_COL);
+str sub_from_tag_col = str_init(SUB_FROM_TAG_COL);
+str sub_to_tag_col = str_init(SUB_TO_TAG_COL);
+str sub_record_route_col = str_init(SUB_RECORD_ROUTE_COL);
+str sub_sockinfo_str_col = str_init(SUB_SOCKINFO_STR_COL);
+
+/*impu_subscriber table*/
+str impu_subscriber_table = str_init(IMPU_SUBSCRIBER_TABLE);
+str subscriber_id_col = str_init(SUBSCRIBER_ID_COL);
+
 str query_buffer 		= { 0, 0 };
-int query_buffer_len 	= 0;
+int query_buffer_len		= 0;
+
+
 
 extern db1_con_t* ul_dbh;
 extern db_func_t ul_dbf;
@@ -210,7 +237,7 @@ int db_insert_ucontact(impurecord_t* _r, ucontact_t* _c) {
 	db_key_t key_return[1];
 	db_val_t* ret_val;
 
-	key_return[0] = &id_column;
+	key_return[0] = &id_col;
 
 	key[0] = &contact_col;
 	key[1] = &path_col;
@@ -349,7 +376,7 @@ int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
 	val[0].type = DB1_STR;
 	val[0].nul = 0;
 	val[0].val.str_val = _r->public_identity;
-	key_return[0] = &id_column;
+	key_return[0] = &id_col;
 
 	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
 		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
@@ -451,6 +478,309 @@ int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c) {
 	return 0;
 }
 
+int db_insert_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber) {
+	db1_res_t* _rs;
+	int subscriber_id;
+	int impu_id;
+	int col_num = 12;
+	db_key_t key[col_num];
+	db_val_t val[col_num];
+	db_key_t key_return[1];
+	db_val_t* ret_val;
+	
+	key_return[0] = &id_col;
+
+	key[0] = &sub_watcher_uri_col;
+	key[1] = &sub_watcher_contact_col;
+	key[2] = &sub_presentity_uri_col;
+	key[3] = &sub_event_col;
+	key[4] = &sub_expires_col;
+	key[5] = &sub_version_col;
+	key[6] = &sub_local_cseq_col;
+	key[7] = &sub_call_id_col;
+	key[8] = &sub_from_tag_col;
+	key[9] = &sub_to_tag_col;
+	key[10] = &sub_record_route_col;
+	key[11] = &sub_sockinfo_str_col;
+
+	val[0].type = DB1_STR;
+	val[0].nul = 0;
+	val[0].val.str_val = _reg_subscriber->watcher_uri;
+
+	val[1].type = DB1_STR;
+	val[1].nul = 0;
+	val[1].val.str_val = _reg_subscriber->watcher_contact;
+
+	val[2].type = DB1_STR;
+	val[2].nul = 0;
+	val[2].val.str_val = _reg_subscriber->presentity_uri;
+
+	val[3].type = DB1_INT;
+	val[3].nul = 0;
+	val[3].val.int_val = _reg_subscriber->event;
+
+	val[4].type = DB1_DATETIME;
+	val[4].nul = 0;
+	val[4].val.time_val = _reg_subscriber->expires;
+
+	val[5].type = DB1_INT;
+	val[5].nul = 0;
+	val[5].val.int_val = _reg_subscriber->version;
+	
+	val[6].type = DB1_INT;
+	val[6].nul = 0;
+	val[6].val.int_val = _reg_subscriber->local_cseq;
+	
+	val[7].type = DB1_STR;
+	val[7].nul = 0;
+	val[7].val.str_val = _reg_subscriber->call_id;
+	
+	val[8].type = DB1_STR;
+	val[8].nul = 0;
+	val[8].val.str_val = _reg_subscriber->from_tag;
+	
+	val[9].type = DB1_STR;
+	val[9].nul = 0;
+	val[9].val.str_val = _reg_subscriber->to_tag;
+	
+	val[10].type = DB1_STR;
+	val[10].nul = 0;
+	val[10].val.str_val = _reg_subscriber->record_route;
+	
+	val[11].type = DB1_STR;
+	val[11].nul = 0;
+	val[11].val.str_val = _reg_subscriber->sockinfo_str;
+
+	if (ul_dbf.use_table(ul_dbh, &subscriber_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", subscriber_table.len, subscriber_table.s);
+		return -1;
+	}
+	if (ul_dbf.insert_update(ul_dbh, key, val, col_num) != 0) {
+		LM_ERR("Failed to insert/update subscriber record for [%.*s]\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+		return -1;
+	}
+	subscriber_id = ul_dbf.last_inserted_id(ul_dbh);
+	if (subscriber_id <= 0) {
+		/* search for the ID if the contact just entered */
+		if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
+			LM_ERR("Unable to find subscriber [%.*s] in DB to complete IMPU-contact mapping\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+			ul_dbf.free_result(ul_dbh, _rs);
+			return -1;
+		}
+
+		if (RES_ROW_N(_rs) == 0) {
+			LM_DBG("Subscriber %.*s not found in DB\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+			ul_dbf.free_result(ul_dbh, _rs);
+			return -1;
+		}
+
+		if (RES_ROW_N(_rs) > 1) {
+			LM_WARN("more than one subscriber found in DB for presentity uri [%.*s] - this should not happen... proceeding with first entry\n",
+				_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+		}
+
+		ret_val = ROW_VALUES(RES_ROWS(_rs));
+		subscriber_id = ret_val[0].val.int_val;
+		ul_dbf.free_result(ul_dbh, _rs);
+	}
+	LM_DBG("Subscriber ID is %d\n", subscriber_id);
+
+	/* search for ID of the associated IMPU */
+	key[0] = &impu_col;
+	val[0].nul = 0;
+	val[0].type = DB1_STR;
+	val[0].val.str_val = _r->public_identity;
+
+	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
+		return -1;
+	}
+	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
+		LM_ERR("Unable to find IMPU [%.*s] in DB to complete IMPU-contact mapping\n", _r->public_identity.len, _r->public_identity.s);
+		return -1;
+	}
+	if (RES_ROW_N(_rs) == 0) {
+		LM_DBG("IMPU %.*s not found in DB\n", _r->public_identity.len, _r->public_identity.s);
+		ul_dbf.free_result(ul_dbh, _rs);
+		return -1;
+	}
+
+	if (RES_ROW_N(_rs) > 1) {
+		LM_WARN("more than one IMPU found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
+				_r->public_identity.len, _r->public_identity.s);
+	}
+	ret_val = ROW_VALUES(RES_ROWS(_rs));
+	impu_id = ret_val[0].val.int_val;
+
+	ul_dbf.free_result(ul_dbh, _rs);
+	LM_DBG("IMPU ID is %d\n", impu_id);
+
+	/* update mapping table between subscriber and IMPU */
+	key[0] = &impu_id_col;
+	key[1] = &subscriber_id_col;
+	val[0].nul = 0;
+	val[0].type = DB1_INT;
+	val[0].val.int_val = impu_id;
+	val[1].nul = 0;
+	val[1].type = DB1_INT;
+	val[1].val.int_val = subscriber_id;
+
+	if (ul_dbf.use_table(ul_dbh, &impu_subscriber_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", impu_subscriber_table.len, impu_subscriber_table.s);
+		return -1;
+	}
+
+	if (ul_dbf.insert_update(ul_dbh, key, val, 2) != 0) {
+		LM_ERR("Failed to insert/update impu-subscriber mapping record for subscriber [%.*s] and impu [%.*s]\n",
+				_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s,
+				_r->public_identity.len, _r->public_identity.s);
+		return -1;
+	}
+	LM_DBG("Inserted subscriber and impu-subscriber mappings for presentity URI: [%.*s] into DB\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+
+	return 0;
+}
+
+
+int db_delete_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber) {
+	db_key_t key[3];
+	db_val_t val[3];
+	
+	db_key_t key_return[1];
+	db_val_t* ret_val;
+	db1_res_t* _rs;
+	int impu_id, subscriber_id;
+
+	LM_DBG("Deleting subscriber binding [%.*s] on impu [%.*s]\n",
+			_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s,
+			_r->public_identity.len, _r->public_identity.s);
+
+	/* get id of IMPU entry */
+	key[0] = &impu_col;
+	val[0].type = DB1_STR;
+	val[0].nul = 0;
+	val[0].val.str_val = _r->public_identity;
+	key_return[0] = &id_col;
+
+	if (ul_dbf.use_table(ul_dbh, &impu_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", impu_table.len, impu_table.s);
+		return -1;
+	}
+	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
+		LM_ERR("Unable to find IMPU [%.*s] in DB to complete IMPU-subscriber mapping\n", _r->public_identity.len, _r->public_identity.s);
+		return -1;
+	}
+	if (RES_ROW_N(_rs) == 0) {
+		LM_DBG("IMPU %.*s not found in DB\n", _r->public_identity.len, _r->public_identity.s);
+		ul_dbf.free_result(ul_dbh, _rs);
+		return -1;
+	}
+	if (RES_ROW_N(_rs) > 1) {
+		LM_WARN("more than one IMPU found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
+				_r->public_identity.len, _r->public_identity.s);
+	}
+	ret_val = ROW_VALUES(RES_ROWS(_rs));
+	impu_id = ret_val[0].val.int_val;
+
+	ul_dbf.free_result(ul_dbh, _rs);
+	LM_DBG("IMPU ID is %d\n", impu_id);
+
+	/* get subscriber id from DB */
+	if (ul_dbf.use_table(ul_dbh, &subscriber_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", subscriber_table.len, subscriber_table.s);
+		return -1;
+	}
+	key[0] = &sub_event_col;
+	val[0].type = DB1_INT;
+	val[0].nul = 0;
+	val[0].val.int_val = _reg_subscriber->event;
+		
+	key[1] = &sub_watcher_contact_col;
+	val[1].type = DB1_STR;
+	val[1].nul = 0;
+	val[1].val.str_val = _reg_subscriber->watcher_contact;
+	
+	key[2] = &sub_presentity_uri_col;
+	val[2].type = DB1_STR;
+	val[2].nul = 0;
+	val[2].val.str_val = _reg_subscriber->presentity_uri;
+	
+	LM_DBG("Looking for subscriber with event: [%d], watcher contact: [%.*s] and presentity URI [%.*s]\n",
+		_reg_subscriber->event,
+		_reg_subscriber->watcher_contact.len, _reg_subscriber->watcher_contact.s,
+		_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+	
+	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 3, 1, NULL, &_rs) != 0) {
+		LM_ERR("Unable to find subscriber [%.*s] in DB to complete IMPU-subscriber mapping removal\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+		return -1;
+	}
+	if (RES_ROW_N(_rs) == 0) {
+		LM_DBG("Subscriber %.*s not found in DB\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+		ul_dbf.free_result(ul_dbh, _rs);
+		return -1;
+	}
+	if (RES_ROW_N(_rs) > 1) {
+		LM_WARN("more than one subscriber found in DB for contact [%.*s] - this should not happen... proceeding with first entry\n",
+				_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+	}
+	ret_val = ROW_VALUES(RES_ROWS(_rs));
+	subscriber_id = ret_val[0].val.int_val;
+	ul_dbf.free_result(ul_dbh, _rs);
+	LM_DBG("subscriber ID is %d\n", subscriber_id);
+
+	LM_DBG("need to remove subscriber-impu mapping %d:%d\n", impu_id, subscriber_id);
+
+	/* update impu-subscribe mapping table */
+	if (ul_dbf.use_table(ul_dbh, &impu_subscriber_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", impu_subscriber_table.len, impu_subscriber_table.s);
+		return -1;
+	}
+	key[0] = &subscriber_id_col;
+	key[1] = &impu_id_col;
+	val[0].type = DB1_INT;
+	val[0].nul = 0;
+	val[0].val.int_val = subscriber_id;
+	val[1].type = DB1_INT;
+	val[1].nul = 0;
+	val[1].val.int_val = impu_id;
+
+	if (ul_dbf.delete(ul_dbh, key, 0, val, 2) != 0) {
+		LM_ERR("unable to remove impu-subscriber mapping from DB for subscriber [%.*s], impu [%.*s]  ..... continuing\n",
+				_reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s,
+				_r->public_identity.len, _r->public_identity.s);
+	}
+
+	/* delete subscriber from subscriber table - IFF there are no more mappings for it to impus */
+	if (ul_dbf.query(ul_dbh, key, 0, val, key_return, 1, 1, NULL, &_rs) != 0) {
+		LM_WARN("error searching for impu-subscriber mappings in DB\n");
+	}
+	if (RES_ROW_N(_rs) > 0) {
+		ul_dbf.free_result(ul_dbh, _rs);
+		LM_DBG("impu-subscriber mappings still exist, not removing subscriber from DB\n");
+		return 0;
+	}
+	ul_dbf.free_result(ul_dbh, _rs);
+
+	key[0] = &id_col;
+	val[0].type = DB1_INT;
+	val[0].nul = 0;
+	val[0].val.int_val = subscriber_id;
+	
+	if (ul_dbf.use_table(ul_dbh, &subscriber_table) != 0) {
+		LM_ERR("Unable to use table [%.*s]\n", subscriber_table.len, subscriber_table.s);
+		return -1;
+	}
+
+	if (ul_dbf.delete(ul_dbh, key, 0, val, 1) != 0) {
+		LM_ERR("unable to remove subscriber from DB [%.*s]\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+	}
+	
+	LM_DBG("Deleted subscriber and impu-subscriber mappings for presentity URI: [%.*s] from DB\n", _reg_subscriber->presentity_uri.len, _reg_subscriber->presentity_uri.s);
+	
+	return 0;
+}
+
+
 int inline int_to_str_len(int i) {
 	if (i < 0)
 		i = -i;
@@ -512,23 +842,122 @@ static inline int dbrow2contact(db_val_t* val, ucontact_info_t* ci) {
 	return 0;
 }
 
+static inline int dbrow2subscriber(db_val_t* val, subscriber_data_t* subscriber_data) {
+	static str presentity_uri, watcher_uri, watcher_contact, call_id, from_tag, to_tag, record_route, sockinfo_str;
+	
+	/*presentity uri*/
+	if (!VAL_NULL(val)) {
+	    presentity_uri.s = (char*) VAL_STRING(val);
+	    presentity_uri.len = strlen(presentity_uri.s);
+	}
+	subscriber_data->presentity_uri = &presentity_uri;
+	LM_DBG("presentity_uri: [%.*s]", subscriber_data->presentity_uri->len, subscriber_data->presentity_uri->s);
+	
+	/*watcher_uri*/
+	if (!VAL_NULL(val + 1)) {
+	    watcher_uri.s = (char*) VAL_STRING(val + 1);
+	    watcher_uri.len = strlen(watcher_uri.s);
+	}
+	subscriber_data->watcher_uri = &watcher_uri;
+	LM_DBG("watcher_uri: [%.*s]", subscriber_data->watcher_uri->len, subscriber_data->watcher_uri->s);
+	
+	/*watcher_contact*/
+	if (!VAL_NULL(val + 2)) {
+	    watcher_contact.s = (char*) VAL_STRING(val + 2);
+	    watcher_contact.len = strlen(watcher_contact.s);
+	}
+	subscriber_data->watcher_contact = &watcher_contact;
+	LM_DBG("watcher_contact: [%.*s]", subscriber_data->watcher_contact->len, subscriber_data->watcher_contact->s);
+	
+	/*event*/
+	if (!VAL_NULL(val + 3)) {
+	    subscriber_data->event = VAL_INT(val + 3);
+	}
+	LM_DBG("event: [%d]", subscriber_data->event);
+	
+	/* expires */
+	if (!VAL_NULL(val + 4)) {
+		subscriber_data->expires = VAL_TIME(val + 4);
+	}
+	LM_DBG("expires: [%d]", subscriber_data->expires);
+	
+	/*event*/
+	if (!VAL_NULL(val + 5)) {
+	    subscriber_data->version = VAL_INT(val + 5);
+	}
+	LM_DBG("version: [%d]", subscriber_data->version);
+	
+	/*local_cseq*/
+	if (!VAL_NULL(val + 6)) {
+	    subscriber_data->local_cseq = VAL_INT(val + 6);
+	}
+	LM_DBG("local_cseq: [%d]", subscriber_data->local_cseq);
+	
+	/* callid */
+	if (!VAL_NULL(val + 7)) {
+		call_id.s = (char*) VAL_STRING(val + 7);
+		call_id.len = strlen(call_id.s);
+	}
+	subscriber_data->callid = &call_id;
+	LM_DBG("callid: [%.*s]", subscriber_data->callid->len, subscriber_data->callid->s);
+	
+	/* ftag */
+	if (!VAL_NULL(val + 8)) {
+		from_tag.s = (char*) VAL_STRING(val + 8);
+		from_tag.len = strlen(from_tag.s);
+	}
+	subscriber_data->ftag = &from_tag;
+	LM_DBG("ftag: [%.*s]", subscriber_data->ftag->len, subscriber_data->ftag->s);
+	
+	/* ttag */
+	if (!VAL_NULL(val + 9)) {
+		to_tag.s = (char*) VAL_STRING(val + 9);
+		to_tag.len = strlen(to_tag.s);
+	}
+	subscriber_data->ttag = &to_tag;
+	LM_DBG("ttag: [%.*s]", subscriber_data->ttag->len, subscriber_data->ttag->s);
+	
+	/* record_route */
+	if (!VAL_NULL(val + 10)) {
+		record_route.s = (char*) VAL_STRING(val + 10);
+		record_route.len = strlen(record_route.s);
+	}
+	subscriber_data->record_route = &record_route;
+	LM_DBG("record_route: [%.*s]", subscriber_data->record_route->len, subscriber_data->record_route->s);
+	
+	/* sockinfo_str */
+	if (!VAL_NULL(val + 11)) {
+		sockinfo_str.s = (char*) VAL_STRING(val + 11);
+		sockinfo_str.len = strlen(sockinfo_str.s);
+	}
+	subscriber_data->sockinfo_str = &sockinfo_str;
+	LM_DBG("sockinfo_str: [%.*s]", subscriber_data->sockinfo_str->len, subscriber_data->sockinfo_str->s);
+	
+	return 0;
+}
+
 int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 	db_key_t col[9];
 	db_row_t* row;
 	db_row_t* contact_row;
+	db_row_t* subscriber_row;
 	db1_res_t* rs;
 	db1_res_t* contact_rs;
+	db1_res_t* subscriber_rs;
 	db_val_t* vals;
 	db_val_t* contact_vals;
+	db_val_t* subscriber_vals;
 	int barring = 0, reg_state = 0, impu_id, n, nn, i, j, len;
-	str query, impu, ccf1 = { 0, 0 }, ecf1 = { 0, 0 }, ccf2 = { 0, 0 }, ecf2 = {
-			0, 0 }, blob = { 0, 0 }, contact={0,0};
+	str query_contact, query_subscriber, impu, ccf1 = { 0, 0 }, ecf1 = { 0, 0 }, ccf2 = { 0, 0 }, ecf2 = {
+			0, 0 }, blob = { 0, 0 }, contact={0,0}, presentity_uri={0,0};
 	bin_data x;
 	ims_subscription* subscription = 0;
 	impurecord_t* impurecord;
 	int impu_id_len;
 	ucontact_t* c;
 	ucontact_info_t contact_data;
+	subscriber_data_t subscriber_data;
+	reg_subscriber *reg_subscriber;
 
 	/*
 	 * the two queries - get the IMPUs, then get associated contacts for each IMPU:
@@ -536,11 +965,19 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 	 * SELECT c.contact,c.path,c.user_agent,c.received,c.expires FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=20;
 	 */
 
-	char *p =
+	char *p_contact =
 			"SELECT c.contact,c.path,c.user_agent,c.received,c.expires,c.callid FROM impu_contact m LEFT JOIN contact c ON c.id=m.contact_id WHERE m.impu_id=";
-
-	query.s = p;
-	query.len = strlen(query.s);
+	
+	char *p_subscriber =
+			"SELECT s.presentity_uri,s.watcher_uri,s.watcher_contact,s.event,s.expires,s.version,s.local_cseq,s.call_id,s.from_tag,"
+	"s.to_tag,s.record_route,s.sockinfo_str FROM impu_subscriber m LEFT JOIN subscriber s ON s.id=m.subscriber_id WHERE m.impu_id=";
+
+	query_contact.s = p_contact;
+	query_contact.len = strlen(query_contact.s);
+	
+	query_subscriber.s = p_subscriber;
+	query_subscriber.len = strlen(query_subscriber.s);
+	
 
 	col[0] = &impu_col;
 	col[1] = &barring_col;
@@ -572,7 +1009,8 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 
 	n = 0;
 	do {
-		LM_DBG("loading S-CSCF usrloc records - cycle [%d]\n", ++n);
+		n++;		
+		LM_DBG("loading S-CSCF usrloc records - cycle [%d]\n", n);
 		for (i = 0; i < RES_ROW_N(rs); i++) {
 			impu_id = -1;
 
@@ -638,13 +1076,13 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 
 			/* add contacts */
 			if (impu_id < 0) {
-				LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts from DB....aborting preload\n", impu.len, impu.s);
+				LM_ERR("impu_id has not been set [%.*s] - we cannot read contacts or subscribers from DB....aborting preload\n", impu.len, impu.s);
 				//TODO: check frees
 				unlock_udomain(_d, &impu);
 				continue;
 			}
 			impu_id_len = int_to_str_len(impu_id);
-			len = query.len + impu_id_len + 1/*nul*/;
+			len = query_contact.len + impu_id_len + 1/*nul*/;
 			if (!query_buffer_len || query_buffer_len < len) {
 				if (query_buffer.s) {
 					pkg_free(query_buffer.s);
@@ -658,61 +1096,131 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 				}
 				query_buffer_len = len;
 			}
-			memcpy(query_buffer.s, query.s, query.len);
-			p = query_buffer.s + query.len;
-			snprintf(p, impu_id_len + 1, "%d", impu_id);
-			query_buffer.len = query.len + impu_id_len;
+			memcpy(query_buffer.s, query_contact.s, query_contact.len);
+			p_contact = query_buffer.s + query_contact.len;
+			snprintf(p_contact, impu_id_len + 1, "%d", impu_id);
+			query_buffer.len = query_contact.len + impu_id_len;
 			if (ul_dbf.raw_query(_c, &query_buffer, &contact_rs) != 0) {
 				LM_ERR("Unable to query DB for contacts associated with impu [%.*s]\n",
 						impu.len, impu.s);
 				ul_dbf.free_result(_c, contact_rs);
+			} else {
+			    if (RES_ROW_N(contact_rs) == 0) {
+				    LM_DBG("no contacts associated with impu [%.*s]\n",impu.len, impu.s);
+				    ul_dbf.free_result(_c, contact_rs);
+			    } else {
+				nn = 0;
+				do {
+					nn++;
+					LM_DBG("loading S-CSCF contact - cycle [%d]\n", nn);
+					for (j = 0; j < RES_ROW_N(contact_rs); j++) {
+						contact_row = RES_ROWS(contact_rs) + j;
+						contact_vals = ROW_VALUES(contact_row);
+
+						if (!VAL_NULL(contact_vals)) {
+							contact.s = (char*) VAL_STRING(contact_vals);
+							contact.len = strlen(contact.s);
+						}
+						if (dbrow2contact(contact_vals, &contact_data) != 0) {
+							LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
+							continue;
+						}
+
+						if ((c = mem_insert_ucontact(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);
+						}
+					}
+					if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
+						if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
+							LM_ERR("fetching rows failed\n");
+							ul_dbf.free_result(_c, contact_rs);
+							unlock_udomain(_d, &impu);
+							return -1;
+						}
+					} else {
+						break;
+					}
+				} while (RES_ROW_N(contact_rs) > 0);
+				ul_dbf.free_result(_c, contact_rs);
+			    }
+			}
+						
+			/* add subscriber */
+			impu_id_len = int_to_str_len(impu_id);
+			len = query_subscriber.len + impu_id_len + 1/*nul*/;
+			if (!query_buffer_len || query_buffer_len < len) {
+				if (query_buffer.s) {
+					pkg_free(query_buffer.s);
+				}
+				query_buffer.s = (char*) pkg_malloc(len);
+				if (!query_buffer.s) {
+					LM_ERR("mo more pkg mem\n");
+					//TODO: check free
+					unlock_udomain(_d, &impu);
+					return -1;
+				}
+				query_buffer_len = len;
+			}
+			memcpy(query_buffer.s, query_subscriber.s, query_subscriber.len);
+			p_subscriber = query_buffer.s + query_subscriber.len;
+			snprintf(p_subscriber, impu_id_len + 1, "%d", impu_id);
+			query_buffer.len = query_subscriber.len + impu_id_len;
+			if (ul_dbf.raw_query(_c, &query_buffer, &subscriber_rs) != 0) {
+				LM_ERR("Unable to query DB for subscriber associated with impu [%.*s]\n",
+						impu.len, impu.s);
+				ul_dbf.free_result(_c, subscriber_rs);
 				unlock_udomain(_d, &impu);
 				continue;
 			}
-			if (RES_ROW_N(contact_rs) == 0) {
-				LM_DBG("no contacts associated with impu [%.*s]\n",impu.len, impu.s);
-				ul_dbf.free_result(_c, contact_rs);
+			if (RES_ROW_N(subscriber_rs) == 0) {
+				LM_DBG("no subscriber associated with impu [%.*s]\n",impu.len, impu.s);
+				ul_dbf.free_result(_c, subscriber_rs);
 				unlock_udomain(_d, &impu);
 				continue;
 			}
 
 			nn = 0;
 			do {
-				LM_DBG("loading S-CSCF contact - cycle [%d]\n", ++nn);
-				for (j = 0; j < RES_ROW_N(contact_rs); j++) {
-					contact_row = RES_ROWS(contact_rs) + j;
-					contact_vals = ROW_VALUES(contact_row);
-
-					if (!VAL_NULL(contact_vals)) {
-						contact.s = (char*) VAL_STRING(contact_vals);
-						contact.len = strlen(contact.s);
+				nn++;				
+				LM_DBG("loading S-CSCF subscriber - cycle [%d]\n", nn);
+				for (j = 0; j < RES_ROW_N(subscriber_rs); j++) {
+					subscriber_row = RES_ROWS(subscriber_rs) + j;
+					subscriber_vals = ROW_VALUES(subscriber_row);
+
+					/*presentity uri*/
+					if (!VAL_NULL(subscriber_vals)) {
+					    presentity_uri.s = (char*) VAL_STRING(subscriber_vals);
+					    presentity_uri.len = strlen(presentity_uri.s);
 					}
-					if (dbrow2contact(contact_vals, &contact_data) != 0) {
-						LM_ERR("unable to convert contact row from DB into valid data... moving on\n");
-						unlock_udomain(_d, &impu);
+
+					if (dbrow2subscriber(subscriber_vals, &subscriber_data) != 0) {
+						LM_ERR("unable to convert subscriber row from DB into valid subscriberdata... moving on\n");
 						continue;
 					}
-
-					if ((c = mem_insert_ucontact(impurecord, &contact, &contact_data)) == 0) {
-						LM_ERR("Unable to insert contact [%.*s] for IMPU [%.*s] into memory... continuing...\n",
-								contact.len, contact.s,
+					
+					if (add_subscriber(impurecord, &subscriber_data, &reg_subscriber, 1 /*db_load*/) != 0) {
+						LM_ERR("Unable to insert subscriber with presentity_uri [%.*s] for IMPU [%.*s] into memory... continuing...\n",
+								presentity_uri.len, presentity_uri.s,
 								impu.len, impu.s);
 					}
 				}
 				if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
-					if (ul_dbf.fetch_result(_c, &contact_rs, ul_fetch_rows) < 0) {
+					if (ul_dbf.fetch_result(_c, &subscriber_rs, ul_fetch_rows) < 0) {
 						LM_ERR("fetching rows failed\n");
-						ul_dbf.free_result(_c, contact_rs);
+						ul_dbf.free_result(_c, subscriber_rs);
 						unlock_udomain(_d, &impu);
 						return -1;
 					}
 				} else {
 					break;
 				}
-			} while (RES_ROW_N(contact_rs) > 0);
-
+			} while (RES_ROW_N(subscriber_rs) > 0);
+			ul_dbf.free_result(_c, subscriber_rs);
+						
 			unlock_udomain(_d, &impu);
-			ul_dbf.free_result(_c, contact_rs);
+			
 		}
 
 		if (DB_CAPABILITY(ul_dbf, DB_CAP_FETCH)) {
@@ -727,6 +1235,8 @@ int preload_udomain(db1_con_t* _c, udomain_t* _d) {
 	} while (RES_ROW_N(rs) > 0);
 
 	ul_dbf.free_result(_c, rs);
+	
+	LM_DBG("Completed preload_udomain");
 
 	return 0;
 }

+ 26 - 0
modules/ims_usrloc_scscf/usrloc_db.h

@@ -31,6 +31,29 @@ extern db_func_t ul_dbf;
 #define ECF2_COL       "ecf2"
 #define IMS_SUB_COL    "ims_subscription_data"
 
+#define IMPU_TABLE  "impu"
+#define CONTACT_TABLE  "contact"
+#define IMPU_CONTACT_TABLE  "impu_contact"
+
+/*subscriber table*/
+#define SUBSCRIBER_TABLE "subscriber"
+#define SUB_EVENT_COL "event"
+#define SUB_EXPIRES_COL "expires"
+#define SUB_VERSION_COL "version"
+#define SUB_WATCHER_URI_COL "watcher_uri"
+#define SUB_WATCHER_CONTACT_COL "watcher_contact"
+#define SUB_PRESENTITY_URI_COL "presentity_uri"
+#define SUB_LOCAL_CSEQ_COL "local_cseq"
+#define SUB_CALL_ID_COL "call_id"
+#define SUB_FROM_TAG_COL "from_tag"
+#define SUB_TO_TAG_COL "to_tag"
+#define SUB_RECORD_ROUTE_COL "record_route"
+#define SUB_SOCKINFO_STR_COL "sockinfo_str"
+
+/*impu subscriber table*/
+#define IMPU_SUBSCRIBER_TABLE "impu_subscriber"
+#define SUBSCRIBER_ID_COL "subscriber_id"
+
 int init_db(const str *db_url, int db_update_period, int fetch_num_rows);
 int connect_db(const str *db_url);
 void destroy_db();
@@ -43,6 +66,9 @@ int db_delete_impurecord(udomain_t* _d, struct impurecord* _r);
 int db_insert_ucontact(impurecord_t* _r, ucontact_t* _c);
 int db_delete_ucontact(impurecord_t* _r, ucontact_t* _c);
 
+int db_insert_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber);
+int db_delete_subscriber(impurecord_t* _r, reg_subscriber* _reg_subscriber);
+
 int preload_udomain(db1_con_t* _c, udomain_t* _d);
 
 #endif /* USRLOC_DB_H_ */