Browse code

Merge 99cab0edf5ab3c93037cd0184d63812c2c13286f into d1a51862440db5c2952833f24576491e811cd622

alexyosifov authored on 21/07/2020 07:42:59 • GitHub committed on 21/07/2020 07:42:59
Showing 9 changed files
... ...
@@ -93,7 +93,7 @@ AAAMessage* cxdx_process_rtr(AAAMessage *rtr) {
93 93
 			impucontact->contact->state = CONTACT_DELETE_PENDING;
94 94
 			if (r->shead) {
95 95
 				//send NOTIFY to all subscribers of this IMPU.
96
-				notify_subscribers(r, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
96
+				notify_subscribers(r, impucontact->contact, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
97 97
 			}
98 98
 			impucontact->contact->state = CONTACT_DELETED;
99 99
 			ul.unlock_contact_slot_i(impucontact->contact->sl);
... ...
@@ -122,7 +122,7 @@ AAAMessage* cxdx_process_rtr(AAAMessage *rtr) {
122 122
 				impucontact->contact->state = CONTACT_DELETE_PENDING;
123 123
 				if (r->shead) {
124 124
 					//send NOTIFY to all subscribers of this IMPU.
125
-					notify_subscribers(r, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
125
+					notify_subscribers(r, impucontact->contact, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
126 126
 				}
127 127
 				impucontact->contact->state = CONTACT_DELETED;
128 128
 				ul.unlock_contact_slot_i(impucontact->contact->sl);
... ...
@@ -66,7 +66,7 @@ static void reg_rpc_dereg_impu(rpc_t* rpc, void* ctx)
66 66
 				impucontact->contact->state = CONTACT_DELETE_PENDING;
67 67
 				if (impu_rec->shead) {
68 68
 						//send NOTIFY to all subscribers of this IMPU.
69
-						notify_subscribers(impu_rec, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
69
+						notify_subscribers(impu_rec, impucontact->contact, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
70 70
 				}
71 71
 				impucontact->contact->state = CONTACT_DELETED;
72 72
 				ul.unlock_contact_slot_i(impucontact->contact->sl);
... ...
@@ -439,7 +439,7 @@ error:
439 439
  * called to deliver new event into notification process
440 440
  * return 0 on success. anything else failure
441 441
  */
442
-int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
442
+int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
443 443
                 str *explit_dereg_contact, int num_explit_dereg_contact) {
444 444
     impurecord_t* r;
445 445
     int num_impus;
... ...
@@ -485,7 +485,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
485 485
             ul.unlock_udomain((udomain_t*) _d, presentity_uri);
486 486
             LM_DBG("About to create notification\n");
487 487
 
488
-            create_notifications(_d, r_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
488
+            create_notifications(_d, r_passed, c_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
489 489
             if (impu_list) {
490 490
                     pkg_free(impu_list);
491 491
             }
... ...
@@ -522,7 +522,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
522 522
 				return 0;
523 523
             }
524 524
             LM_DBG("About to create notification\n");
525
-            create_notifications(_d, r_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
525
+            create_notifications(_d, r_passed, c_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
526 526
             if (impu_list) {
527 527
                     pkg_free(impu_list);
528 528
             }
... ...
@@ -535,8 +535,8 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
535 535
     }
536 536
 }
537 537
 
538
-int notify_subscribers(impurecord_t* impurecord, str *explit_dereg_contact, int num_explit_dereg_contact, int event_type) {
539
-    event_reg(0, impurecord, event_type, 0, 0, 0, explit_dereg_contact, num_explit_dereg_contact);
538
+int notify_subscribers(impurecord_t* impurecord, ucontact_t* contact, str *explit_dereg_contact, int num_explit_dereg_contact, int event_type) {
539
+    event_reg(0, impurecord, contact, event_type, 0, 0, 0, explit_dereg_contact, num_explit_dereg_contact);
540 540
 
541 541
     return 0;
542 542
 }
... ...
@@ -594,7 +594,7 @@ int process_contact(ims_subscription* subscription, udomain_t * _d, int expires,
594 594
                         ucontact->state = CONTACT_DELETE_PENDING;
595 595
                         if (implicit_impurecord->shead) {
596 596
                             //send NOTIFY to all subscribers of this IMPU.
597
-                            notify_subscribers(implicit_impurecord, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
597
+                            notify_subscribers(implicit_impurecord, ucontact, 0, 0, IMS_REGISTRAR_CONTACT_UNREGISTERED);
598 598
                         }
599 599
                         ul.unlock_contact_slot(&contact_uri);
600 600
                         //                        if (ul.unlink_contact_from_impu(implicit_impurecord, ucontact, 1, 0 /*implicit dereg of contact from IMPU*/) != 0) {
... ...
@@ -1071,7 +1071,7 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
1071 1071
         LM_DBG("Got to tag from sent response: [%.*s]\n", ttag.len, ttag.s);
1072 1072
         LM_DBG("This is initial subscribe - get presentity URI from req URI\n");
1073 1073
         presentity_uri = cscf_get_public_identity_from_requri(msg);
1074
-
1074
+		event_type = IMS_REGISTRAR_SUBSCRIBE;
1075 1075
     } else {
1076 1076
         LM_DBG("Msg has ttag: [%.*s] - this is subsequent subscribe\n", ttag.len, ttag.s);
1077 1077
         //cscf_get_to_uri(msg, &presentity_uri);
... ...
@@ -1085,6 +1085,7 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
1085 1085
             ret = CSCF_RETURN_FALSE;
1086 1086
             goto doneorerror;
1087 1087
         }
1088
+		event_type = IMS_REGISTRAR_SUBSEQUENT_SUBSCRIBE;
1088 1089
     }
1089 1090
 
1090 1091
     //get cseq
... ...
@@ -1147,7 +1148,6 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
1147 1148
 
1148 1149
     if (expires > 0) {
1149 1150
         LM_DBG("expires is more than zero - SUBSCRIBE\n");
1150
-        event_type = IMS_REGISTRAR_SUBSCRIBE;
1151 1151
 
1152 1152
         if (expires < subscription_min_expires) expires = subscription_min_expires;
1153 1153
         if (expires > subscription_max_expires) expires = subscription_max_expires;
... ...
@@ -1220,14 +1220,16 @@ int subscribe_to_reg(struct sip_msg *msg, char *_t, char *str2) {
1220 1220
         LM_DBG("Sending 200 OK to subscribing user\n");
1221 1221
         subscribe_reply(msg, 200, MSG_REG_SUBSCRIBE_OK, &expires, &scscf_name_str);
1222 1222
 
1223
-        //do reg event every time you get a subscribe
1224
-        if (event_reg(domain, 0, event_type, &presentity_uri, &watcher_contact, 0, 0, 0) != 0) {
1225
-            LM_ERR("failed adding notification for reg events\n");
1226
-            ret = CSCF_RETURN_ERROR;
1227
-            goto doneorerror;
1228
-        } else {
1229
-            LM_DBG("success adding notification for reg events\n");
1230
-        }
1223
+		if(event_type == IMS_REGISTRAR_SUBSCRIBE) {
1224
+			//do reg event only for the initial subscribe
1225
+			if (event_reg(domain, 0, 0, event_type, &presentity_uri, &watcher_contact, 0, 0, 0) != 0) {
1226
+				LM_ERR("failed adding notification for reg events\n");
1227
+				ret = CSCF_RETURN_ERROR;
1228
+				goto doneorerror;
1229
+			} else {
1230
+				LM_DBG("success adding notification for reg events\n");
1231
+			}
1232
+		}
1231 1233
     } else {
1232 1234
         event_type = IMS_REGISTRAR_UNSUBSCRIBE;
1233 1235
         LM_DBG("expires is zero or less - UNSUBSCRIBE\n");
... ...
@@ -1467,7 +1469,7 @@ static str subs_active = {"active;expires=", 15};
1467 1469
  * @param content - the body content
1468 1470
  * @param expires - the remaining subcription expiration time in seconds
1469 1471
  */
1470
-void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
1472
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
1471 1473
                             str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact) {
1472 1474
 
1473 1475
     reg_notification *n;
... ...
@@ -1534,26 +1536,34 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity
1534 1536
                 LM_DBG("This is a fix to ensure that we only send full reg info XML to the UE that just subscribed.\n");
1535 1537
                 create_notification = 1;
1536 1538
             }
1537
-        } else {
1538
-            if (event_type == IMS_REGISTRAR_CONTACT_REGISTERED) {
1539
-                if(contact_match(contact_uri, &s->watcher_contact) &&
1540
-                    (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)) {
1541
-                    LM_DBG("This is a fix to ensure that we only send full reg info XML to the UE that just subscribed.\n");
1542
-                    create_notification = 1;
1543
-                }
1544
-            } else {
1545
-            //TODO: we must make this optimisation to not send NOTIFYs back to UE's *(they may have disappeared)
1546
-            //            if (event_type == IMS_REGISTRAR_CONTACT_UNREGISTERED && !ue_unsubscribe_on_dereg /*&&
1547
-            //                    (contact_port_ip_match(&c_passed->c, &s->watcher_contact) */
1548
-            //                    && (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)) {
1549
-            //                //if this is UNREGISTER and the UEs do not unsubscribe to dereg and this is a UE subscribing to its own reg event
1550
-            //                //then we do not send notifications
1551
-            //                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");
1552
-            //            } else {
1553
-            //            }
1539
+        } else if (event_type == IMS_REGISTRAR_CONTACT_REGISTERED || event_type == IMS_REGISTRAR_CONTACT_REFRESHED) {
1540
+			if(contact_match(contact_uri, &s->watcher_contact) &&
1541
+				(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)) {
1542
+				LM_DBG("This is a fix to ensure that we only send full reg info XML to the UE that just registered.\n");
1554 1543
 				create_notification = 1;
1555 1544
 			}
1556
-        }
1545
+		} else if (event_type == IMS_REGISTRAR_CONTACT_EXPIRED || event_type == IMS_REGISTRAR_CONTACT_UNREGISTERED) {
1546
+			if(!ue_unsubscribe_on_dereg &&
1547
+				contact_port_ip_match(&c_passed->c, &s->watcher_contact) && alias_port_ip_match(&c_passed->c, &s->watcher_contact) &&
1548
+				r_passed->public_identity.len == s->presentity_uri.len &&
1549
+				memcmp(s->presentity_uri.s, r_passed->public_identity.s, r_passed->public_identity.len) == 0) {
1550
+				LM_DBG("This is a UNREGISTER/EXPIRE event for a UE that subscribed to its own state that does not unsubscribe to dereg - therefore no notification\n");
1551
+
1552
+				if(r->linked_contacts.numcontacts < 2) {
1553
+					// marking the contact as Notify ready if there aren't other linked contacts to the current impu record
1554
+					ul.lock_contact_slot_i(c_passed->sl);
1555
+					if(c_passed->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
1556
+						LM_DBG("Setting contact state from CONTACT_EXPIRE_PENDING_NOTIFY to CONTACT_NOTIFY_READY for contact [%.*s]\n", c_passed->c.len, c_passed->c.s);
1557
+						c_passed->state = CONTACT_NOTIFY_READY;
1558
+					}
1559
+					ul.unlock_contact_slot_i(c_passed->sl);
1560
+				}
1561
+			} else {
1562
+				create_notification = 1;
1563
+			}
1564
+		} else {
1565
+			create_notification = 1;
1566
+		}
1557 1567
 
1558 1568
         if(create_notification) {
1559 1569
             LM_DBG("About to make new notification! We always increment the local cseq and version before we send a new notification\n");
... ...
@@ -1750,7 +1760,7 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *exp
1750 1760
     str buf, pad;
1751 1761
     char bufc[MAX_REGINFO_SIZE], padc[MAX_REGINFO_SIZE];
1752 1762
     impurecord_t *r;
1753
-    int i, k, res, added_contacts;
1763
+    int i, k, res;
1754 1764
     ucontact_t* ptr;
1755 1765
 
1756 1766
     buf.s = bufc;
... ...
@@ -1762,6 +1772,10 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *exp
1762 1772
     int terminate_impu = 1;
1763 1773
 	impu_contact_t *impucontact;
1764 1774
 
1775
+	unsigned int num_pending_notify_contacts = 0;
1776
+	unsigned int max_num_pending_notify_contacts = 0;
1777
+	ucontact_t** pending_notify_contacts = 0;
1778
+
1765 1779
     LM_DBG("Getting reginfo_full\n");
1766 1780
 
1767 1781
     STR_APPEND(buf, xml_start);
... ...
@@ -1769,6 +1783,28 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *exp
1769 1783
     pad.len = strlen(pad.s);
1770 1784
     STR_APPEND(buf, pad);
1771 1785
 
1786
+	// reserve memory for all contacts for all impus
1787
+	for (i = 0; i < num_impus; i++) {
1788
+		ul.lock_udomain(_t, &impu_list[i]);
1789
+
1790
+		res = ul.get_impurecord(_t, (&impu_list[i]), &r);
1791
+		if (res != 0) {
1792
+			LM_DBG("impu disappeared, ignoring it\n");
1793
+			ul.unlock_udomain(_t, &impu_list[i]);
1794
+			continue;
1795
+		}
1796
+
1797
+		max_num_pending_notify_contacts += r->linked_contacts.numcontacts;
1798
+
1799
+		ul.unlock_udomain(_t, &impu_list[i]);
1800
+	}
1801
+
1802
+	pending_notify_contacts = (ucontact_t**)pkg_malloc(max_num_pending_notify_contacts*sizeof(ucontact_t**));
1803
+	if (!pending_notify_contacts) {
1804
+		LM_WARN("no more pkg mem trying to allocate [%lu] bytes\n", max_num_pending_notify_contacts*sizeof(ucontact_t**));
1805
+		max_num_pending_notify_contacts = 0;
1806
+	}
1807
+
1772 1808
     for (i = 0; i < num_impus; i++) {
1773 1809
         LM_DBG("Scrolling through public identities, current one <%.*s>\n", impu_list[i].len, impu_list[i].s);
1774 1810
         //        if (primary_locked && strncasecmp(impu_list[i].s, primary_impu->s, impu_list[i].len) == 0) {
... ...
@@ -1834,31 +1870,20 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *exp
1834 1870
         }
1835 1871
 
1836 1872
 		impucontact = r->linked_contacts.head;
1837
-		added_contacts = 0;
1838 1873
 		while (impucontact) {
1839 1874
 			ptr = impucontact->contact;
1840 1875
 
1841
-			// Prevent multiple contacts in Notify message body <registration> tags
1842
-			// 1. Compare contact->contact IP and PORT with subscriber->watcher_contact IP and PORT
1843
-			// 2. Compare contact->contact alias IP and PORT with subscriber->watcher_contact alias IP and PORT without PROTO
1844
-			// This is because of IPv6 and IPv4 family
1845
-			// When we have a case like: UE <--IPv6--> P-CSCF <--IPv4--> S-CSCF
1846
-			// Then scscf contact->contact alias proto is 2(IPv6) but scscf subscriber->watcher_contact alias proto is 1(IPv4)
1847
-			if(contact_port_ip_match(&ptr->c, watcher_contact) && alias_port_ip_match(&ptr->c, watcher_contact)){
1848
-				process_xml_for_contact(&buf, &pad, ptr);
1849
-				++added_contacts;
1850
-			}
1851
-			impucontact = impucontact->next;
1852
-		}
1876
+			ul.lock_contact_slot_i(ptr->sl);
1853 1877
 
1854
-		// For pcscf or other AS subscriptions add all contacts
1855
-		if(added_contacts == 0) {
1856
-			impucontact = r->linked_contacts.head;
1857
-			while (impucontact) {
1858
-				ptr = impucontact->contact;
1859
-				process_xml_for_contact(&buf, &pad, ptr);
1860
-				impucontact = impucontact->next;
1878
+			process_xml_for_contact(&buf, &pad, ptr);
1879
+
1880
+			if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY && num_pending_notify_contacts < max_num_pending_notify_contacts) {
1881
+				pending_notify_contacts[num_pending_notify_contacts++] = ptr;
1861 1882
 			}
1883
+
1884
+			ul.unlock_contact_slot_i(ptr->sl);
1885
+
1886
+			impucontact = impucontact->next;
1862 1887
 		}
1863 1888
 
1864 1889
         STR_APPEND(buf, registration_e);
... ...
@@ -1868,6 +1893,23 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int num_impus, str *exp
1868 1893
         //        }
1869 1894
     }
1870 1895
 
1896
+	// set all expire pending notify contacts to notify ready state
1897
+	for (i = 0; i < num_pending_notify_contacts; ++i) {
1898
+		ptr = pending_notify_contacts[i];
1899
+		ul.lock_contact_slot_i(ptr->sl);
1900
+
1901
+		if(ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
1902
+			LM_DBG("Setting contact state from CONTACT_EXPIRE_PENDING_NOTIFY to CONTACT_NOTIFY_READY for contact [%.*s]\n", ptr->c.len, ptr->c.s);
1903
+			ptr->state = CONTACT_NOTIFY_READY;
1904
+		}
1905
+
1906
+		ul.unlock_contact_slot_i(ptr->sl);
1907
+	}
1908
+
1909
+	if (pending_notify_contacts){
1910
+		pkg_free(pending_notify_contacts);
1911
+	}
1912
+
1871 1913
     STR_APPEND(buf, r_reginfo_e);
1872 1914
 
1873 1915
     x.s = pkg_malloc(buf.len + 1);
... ...
@@ -79,7 +79,7 @@ typedef struct _reg_notification {
79 79
     
80 80
     str *explit_dereg_contact;
81 81
     int num_explit_dereg_contact;
82
-    
82
+
83 83
     struct _reg_notification *next; /**< next notification in the list	*/
84 84
     struct _reg_notification *prev; /**< previous notification in the list	*/
85 85
 } reg_notification;
... ...
@@ -116,6 +116,7 @@ typedef enum {
116 116
     IMS_REGISTRAR_CONTACT_EXPIRED, /**< A contact has expired and will be removed		*/
117 117
     IMS_REGISTRAR_CONTACT_UNREGISTERED, /**< User unregistered with Expires 0				*/
118 118
     IMS_REGISTRAR_CONTACT_UNREGISTERED_IMPLICIT, /**< User unregistered implicitly, ie not via explicit deregister	*/
119
+	IMS_REGISTRAR_SUBSEQUENT_SUBSCRIBE
119 120
 } IMS_Registrar_events_enum_t;
120 121
 
121 122
 extern IMS_Registrar_events_enum_t IMS_Registrar_events;
... ...
@@ -132,7 +133,7 @@ int publish_reg(struct sip_msg *msg, char *str1, char *str2);
132 133
 
133 134
 int subscribe_reply(struct sip_msg *msg, int code, char *text, int *expires, str *contact);
134 135
 
135
-int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
136
+int event_reg(udomain_t* _d, impurecord_t* r_passed, ucontact_t* c_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
136 137
                 str *explit_dereg_contact, int num_explit_dereg_contact);
137 138
 
138 139
 
... ...
@@ -140,7 +141,7 @@ str generate_reginfo_full(udomain_t* _t, str* impu_list, int new_subscription, s
140 141
 
141 142
 str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type, unsigned int reginfo_version);
142 143
 
143
-void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
144
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, ucontact_t* c_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
144 145
                             str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact);
145 146
 
146 147
 void notification_event_process();
... ...
@@ -163,6 +164,6 @@ void notify_destroy();
163 164
 int aor_to_contact(str* aor, str* contact);
164 165
 int contact_port_ip_match(str *c1, str *c2);
165 166
 
166
-int notify_subscribers(impurecord_t* impurecord, str *explit_dereg_contact, int num_explit_dereg_contact, int event_type);
167
+int notify_subscribers(impurecord_t* impurecord, ucontact_t* contact, str *explit_dereg_contact, int num_explit_dereg_contact, int event_type);
167 168
 
168 169
 #endif //S_CSCF_REGISTRAR_NOTIFY_H_
... ...
@@ -777,6 +777,9 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
777 777
     int first_unbarred_impu = 1; //this is used to flag the IMPU as anchor for implicit set
778 778
     int is_primary_impu = 0;
779 779
     int ret = 1;
780
+	str callid = {0, 0};
781
+	str path = {0, 0};
782
+	ucontact_t* ucontact;
780 783
 
781 784
     int num_explicit_dereg_contact = 0;
782 785
     str *explicit_dereg_contact = 0;
... ...
@@ -835,7 +838,12 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
835 838
             for (h = msg->contact; h; h = h->next) {
836 839
                 if (h->type == HDR_CONTACT_T && h->parsed) {
837 840
                     for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
838
-                        event_reg(0, impu_rec, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0, &chi->uri, 0, 0);
841
+						if (ul.get_ucontact(&chi->uri, &callid, &path, 0, &ucontact) != 0) {
842
+							LM_DBG("Contact does not exist <%.*s>\n", chi->uri.len, chi->uri.s);
843
+							goto error;
844
+						}
845
+                        event_reg(0, impu_rec, ucontact, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0, &chi->uri, 0, 0);
846
+						ul.release_ucontact(ucontact);
839 847
                     }
840 848
                 }
841 849
             }
... ...
@@ -927,7 +935,12 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
927 935
             for (h = msg->contact; h; h = h->next) {
928 936
                 if (h->type == HDR_CONTACT_T && h->parsed) {
929 937
                     for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
930
-                        event_reg(0, impu_rec, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0, &chi->uri, 0, 0);
938
+						if (ul.get_ucontact(&chi->uri, &callid, &path, 0, &ucontact) != 0) {
939
+							LM_DBG("Contact does not exist <%.*s>\n", chi->uri.len, chi->uri.s);
940
+							goto error;
941
+						}
942
+                        event_reg(0, impu_rec, ucontact, IMS_REGISTRAR_CONTACT_REFRESHED, 0, 0, &chi->uri, 0, 0);
943
+						ul.release_ucontact(ucontact);
931 944
                     }
932 945
                 }
933 946
             }
... ...
@@ -1029,11 +1042,17 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
1029 1042
                         //                                s = s->next;
1030 1043
                         //                            }
1031 1044
                         //                        }
1032
-                        notify_subscribers(tmp_impu_rec, (str*) explicit_dereg_contact, num_explicit_dereg_contact, IMS_REGISTRAR_CONTACT_UNREGISTERED);
1033 1045
 
1034 1046
                         for (h = msg->contact; h; h = h->next) {
1035 1047
                             if (h->type == HDR_CONTACT_T && h->parsed) {
1036 1048
                                 for (chi = ((contact_body_t*) h->parsed)->contacts; chi; chi = chi->next) {
1049
+									if (ul.get_ucontact(&chi->uri, &callid, &path, 0, &ucontact) != 0) {
1050
+										LM_DBG("Contact does not exist <%.*s>\n", chi->uri.len, chi->uri.s);
1051
+										goto error;
1052
+									}
1053
+									notify_subscribers(tmp_impu_rec, ucontact, (str*) explicit_dereg_contact, num_explicit_dereg_contact, IMS_REGISTRAR_CONTACT_UNREGISTERED);
1054
+									ul.release_ucontact(ucontact);
1055
+
1037 1056
                                     if (calc_contact_q(chi->q, &qvalue) != 0) {
1038 1057
                                         LM_ERR("error on <%.*s>\n", chi->uri.len, chi->uri.s);
1039 1058
                                         ul.unlock_udomain(_d, &pi->public_identity);
... ...
@@ -94,6 +94,9 @@ void ul_contact_changed(impurecord_t* r, ucontact_t* c, int type, void* param) {
94 94
 //    
95 95
     if (type == UL_IMPU_DELETE_CONTACT) {
96 96
         LM_DBG("Received notification of UL CONTACT DELETE\n");
97
-        event_reg(0, r, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0, 0, 0, 0);
97
+        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0, 0, 0, 0);
98
+    } else if (type == UL_IMPU_EXPIRE_CONTACT) {
99
+        LM_DBG("Received notification of UL CONTACT EXPIRED\n");
100
+        event_reg(0, r, c, IMS_REGISTRAR_CONTACT_EXPIRED, 0, 0, 0, 0, 0);
98 101
     }
99 102
 }
... ...
@@ -368,39 +368,6 @@ static inline void process_impurecord(impurecord_t* _r) {
368 368
 
369 369
     get_act_time();
370 370
 
371
-    s = _r->shead;
372
-    LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s);
373
-    while (s) {
374
-		next = s->next;
375
-        if (!valid_subscriber(s, act_time)) {
376
-            LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n",
377
-                    s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s);
378
-            if (!dbwork) {
379
-                start_dbtransaction();
380
-                dbwork = 1;
381
-            }
382
-            delete_subscriber(_r, s);
383
-        } else {
384
-            LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n",
385
-                    s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s,
386
-                    (unsigned int) (s->expires - time(NULL)));
387
-            sl = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size);
388
-            LM_DBG("Hash size: <%i>\n", sub_dialog_hash_size);
389
-            LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>\n", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, sl);
390
-            /* search the record in hash table */
391
-            lock_get(&sub_dialog_table[sl].lock);
392
-            sub_dialog = pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, sl);
393
-            if (sub_dialog == NULL) {
394
-                LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n");
395
-            } else {
396
-                LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s);
397
-            }
398
-            lock_release(&sub_dialog_table[sl].lock);
399
-            mustdeleteimpu = 0;
400
-        }
401
-        s = next;
402
-    }
403
-
404 371
     LM_DBG("\tPublic Identity %.*s, Barred: [%d], State: [%s], contacts [%d], 3gppcontacts [%d]\n",
405 372
             _r->public_identity.len, _r->public_identity.s,
406 373
             _r->barring,
... ...
@@ -422,9 +389,9 @@ static inline void process_impurecord(impurecord_t* _r) {
422 389
 				num_contacts_to_expire++;
423 390
 			} else if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
424 391
 				LM_DBG("Contact: <%.*s> is in state CONTACT_EXPIRE_PENDING_NOTIFY....running callback\n", ptr->c.len, ptr->c.s);
425
-				if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) {
426
-					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);
427
-					run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, ptr);
392
+				if (exists_ulcb_type(_r->cbs, UL_IMPU_EXPIRE_CONTACT)) {
393
+					LM_DBG("Running callback UL_IMPU_EXPIRE_CONTACT for contact [%.*s] and impu [%.*s]\n", ptr->c.len, ptr->c.s, _r->public_identity.len, _r->public_identity.s);
394
+					run_ul_callbacks(_r->cbs, UL_IMPU_EXPIRE_CONTACT, _r, ptr);
428 395
 				}
429 396
 				hascontacts = 1;    // we do this because the impu must only be deleted if in state deleted....
430 397
 				mustdeleteimpu = 0;
... ...
@@ -463,6 +430,39 @@ static inline void process_impurecord(impurecord_t* _r) {
463 430
         }
464 431
     }
465 432
 
433
+	s = _r->shead;
434
+    LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s);
435
+    while (s) {
436
+		next = s->next;
437
+        if (!valid_subscriber(s, act_time)) {
438
+            LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n",
439
+                    s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s);
440
+            if (!dbwork) {
441
+                start_dbtransaction();
442
+                dbwork = 1;
443
+            }
444
+            delete_subscriber(_r, s);
445
+        } else {
446
+            LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n",
447
+                    s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s,
448
+                    (unsigned int) (s->expires - time(NULL)));
449
+            sl = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size);
450
+            LM_DBG("Hash size: <%i>\n", sub_dialog_hash_size);
451
+            LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>\n", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, sl);
452
+            /* search the record in hash table */
453
+            lock_get(&sub_dialog_table[sl].lock);
454
+            sub_dialog = pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, sl);
455
+            if (sub_dialog == NULL) {
456
+                LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n");
457
+            } else {
458
+                LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s);
459
+            }
460
+            lock_release(&sub_dialog_table[sl].lock);
461
+            mustdeleteimpu = 0;
462
+        }
463
+        s = next;
464
+    }
465
+
466 466
     if (!flag)
467 467
         LM_DBG("no contacts\n");
468 468
 
... ...
@@ -331,8 +331,19 @@ void mem_timer_udomain(udomain_t* _d, int istart, int istep) {
331 331
 								LM_DBG("contact in state CONTACT_DELAYED_DELETE still has a ref count of [%d] in memory. Not doing anything for now \n", contact_ptr->ref_count);
332 332
 							}
333 333
                         }
334
-                    } else if (contact_ptr->state != CONTACT_DELETED) {
335
-                        LM_DBG("expiring contact [%.*s](%.*s).... setting to CONTACT_EXPIRE_PENDING_NOTIFY\n",
334
+                    } else if (contact_ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
335
+						LM_DBG("expired pending notify contact [%.*s](%.*s).... setting to CONTACT_NOTIFY_READY\n",
336
+								contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s);
337
+						contact_ptr->state = CONTACT_NOTIFY_READY;
338
+						expired_contacts[num_expired_contacts] = contact_ptr;
339
+						num_expired_contacts++;
340
+					} else if (contact_ptr->state == CONTACT_NOTIFY_READY) {
341
+						LM_DBG("expired notify ready contact [%.*s](%.*s).... marking for deletion\n",
342
+								contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s);
343
+						expired_contacts[num_expired_contacts] = contact_ptr;
344
+						num_expired_contacts++;
345
+					} else if (contact_ptr->state != CONTACT_DELETED) {
346
+						LM_DBG("expiring contact [%.*s](%.*s).... setting to CONTACT_EXPIRE_PENDING_NOTIFY\n",
336 347
 								contact_ptr->aor.len, contact_ptr->aor.s, contact_ptr->c.len, contact_ptr->c.s);
337 348
                         contact_ptr->state = CONTACT_EXPIRE_PENDING_NOTIFY;
338 349
                         ref_contact_unsafe(contact_ptr);
... ...
@@ -399,16 +410,22 @@ void mem_timer_udomain(udomain_t* _d, int istart, int istep) {
399 410
         for (i=0; i<num_expired_contacts; i++) {
400 411
             slot = expired_contacts[i]->sl;
401 412
             lock_contact_slot_i(slot);
402
-            if (expired_contacts[i]->state != CONTACT_DELAYED_DELETE) {
403
-                LM_DBG("Setting contact state to CONTACT_DELETED for contact [%.*s](%.*s)\n",
413
+			if(expired_contacts[i]->state == CONTACT_EXPIRE_PENDING_NOTIFY) {
414
+				LM_DBG("Contact state CONTACT_EXPIRE_PENDING_NOTIFY for contact [%.*s](%.*s)\n",
404 415
 						expired_contacts[i]->aor.len, expired_contacts[i]->aor.s, expired_contacts[i]->c.len, expired_contacts[i]->c.s);
405
-                expired_contacts[i]->state = CONTACT_DELETED;
406
-                unref_contact_unsafe(expired_contacts[i]);
407
-            } else {
408
-                LM_DBG("deleting contact [%.*s](%.*s)\n",
409
-						expired_contacts[i]->aor.len, expired_contacts[i]->aor.s, expired_contacts[i]->c.len, expired_contacts[i]->c.s);
410
-                delete_scontact(expired_contacts[i]);
411
-            }
416
+			} else {
417
+				if (expired_contacts[i]->state != CONTACT_DELAYED_DELETE) {
418
+					LM_DBG("Setting contact state from '%s' to CONTACT_DELETED for contact [%.*s](%.*s)\n",
419
+							get_contact_state_as_string(expired_contacts[i]->state),
420
+							expired_contacts[i]->aor.len, expired_contacts[i]->aor.s, expired_contacts[i]->c.len, expired_contacts[i]->c.s);
421
+					expired_contacts[i]->state = CONTACT_DELETED;
422
+					unref_contact_unsafe(expired_contacts[i]);
423
+				} else {
424
+					LM_DBG("deleting contact [%.*s](%.*s)\n",
425
+							expired_contacts[i]->aor.len, expired_contacts[i]->aor.s, expired_contacts[i]->c.len, expired_contacts[i]->c.s);
426
+					delete_scontact(expired_contacts[i]);
427
+				}
428
+			}
412 429
             unlock_contact_slot_i(slot);
413 430
         }
414 431
     }
... ...
@@ -146,11 +146,12 @@ typedef enum contact_state {
146 146
     CONTACT_DELETE_PENDING,
147 147
     CONTACT_EXPIRE_PENDING_NOTIFY,
148 148
     CONTACT_DELETED,
149
-    CONTACT_DELAYED_DELETE
149
+    CONTACT_DELAYED_DELETE,
150
+	CONTACT_NOTIFY_READY /**< Prevents deletion of a contact before construction of notify body */
150 151
 } contact_state_t;
151 152
 
152 153
 /*! \brief Valid contact is a contact that either didn't expire yet or is permanent */
153
-#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 && c->state!=CONTACT_DELAYED_DELETE)
154
+#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 && c->state!=CONTACT_DELAYED_DELETE && c->state!=CONTACT_NOTIFY_READY)
154 155
 
155 156
 #define VALID_UE_TYPE(c, t)   ((t==0) || (t==1 && c->is_3gpp) || (t==2 && !c->is_3gpp))
156 157
 
... ...
@@ -405,6 +406,8 @@ static inline char* get_contact_state_as_string(enum contact_state c_state) {
405 406
             return "Contact deleted";
406 407
         case CONTACT_DELAYED_DELETE:
407 408
             return "Contact with delayed delete";
409
+		case CONTACT_NOTIFY_READY:
410
+			return "Contact expired with prepared NOTIFY";
408 411
         default:
409 412
             return "unknown";
410 413
     }