ims_registrar_scscf: fix multiple contacts in 200OK
authorAleksandar Yosifov <alexyosifov@gmail.com>
Thu, 7 May 2020 12:51:34 +0000 (15:51 +0300)
committerHenning Westerholt <hw@skalatan.de>
Wed, 20 May 2020 06:28:06 +0000 (08:28 +0200)
- Prevent sending of multiple contacts in 200OK reply
  for UE Re-Registration. Now S-CSCF replies with the
  exact contact for Re-Registration.

src/modules/ims_registrar_scscf/registrar_notify.c
src/modules/ims_registrar_scscf/registrar_notify.h
src/modules/ims_registrar_scscf/reply.c
src/modules/ims_registrar_scscf/reply.h
src/modules/ims_registrar_scscf/save.c
src/modules/ims_registrar_scscf/usrloc_cb.c

index a623792..dfcec90 100644 (file)
@@ -439,7 +439,8 @@ 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, int event_type, str *presentity_uri, str *watcher_contact, str *explit_dereg_contact, int num_explit_dereg_contact) {
+int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
+                str *explit_dereg_contact, int num_explit_dereg_contact) {
     impurecord_t* r;
     int num_impus;
     str* impu_list = 0;
@@ -484,7 +485,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
             ul.unlock_udomain((udomain_t*) _d, presentity_uri);
             LM_DBG("About to create notification\n");
 
-            create_notifications(_d, r_passed, presentity_uri, watcher_contact, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
+            create_notifications(_d, r_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
             if (impu_list) {
                     pkg_free(impu_list);
             }
@@ -498,7 +499,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
         case IMS_REGISTRAR_CONTACT_REFRESHED:
         case IMS_REGISTRAR_CONTACT_EXPIRED:
             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");
+                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\n");
                 return 0;
             }
             //this is a ulcallback so r_passed domain is already locked
@@ -521,7 +522,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
                                return 0;
             }
             LM_DBG("About to create notification\n");
-            create_notifications(_d, r_passed, presentity_uri, watcher_contact, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
+            create_notifications(_d, r_passed, presentity_uri, watcher_contact, contact_uri, impu_list, num_impus, event_type, explit_dereg_contact, num_explit_dereg_contact);
             if (impu_list) {
                     pkg_free(impu_list);
             }
@@ -535,7 +536,7 @@ int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presen
 }
 
 int notify_subscribers(impurecord_t* impurecord, str *explit_dereg_contact, int num_explit_dereg_contact, int event_type) {
-    event_reg(0, impurecord, event_type, 0, 0, explit_dereg_contact, num_explit_dereg_contact);
+    event_reg(0, impurecord, event_type, 0, 0, 0, explit_dereg_contact, num_explit_dereg_contact);
 
     return 0;
 }
@@ -1220,7 +1221,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, event_type, &presentity_uri, &watcher_contact, 0, 0) != 0) {
+        if (event_reg(domain, 0, event_type, &presentity_uri, &watcher_contact, 0, 0, 0) != 0) {
             LM_ERR("failed adding notification for reg events\n");
             ret = CSCF_RETURN_ERROR;
             goto doneorerror;
@@ -1466,13 +1467,15 @@ 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, str *presentity_uri, str *watcher_contact, str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact) {
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
+                            str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact) {
 
     reg_notification *n;
     reg_subscriber *s;
     impurecord_t* r;
     int local_cseq = 0;
     int version = 0;
+    int create_notification;
 
     str subscription_state = {"active;expires=10000000000", 26},
     content_type = {"application/reginfo+xml", 23};
@@ -1503,7 +1506,9 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity
 
     s = r->shead;
     while (s) {
-        LM_DBG("Scrolling through reg subscribers for this IMPU\n");
+        LM_DBG("Scrolling through reg subscribers for this IMPU [%.*s]\n", r->public_identity.len, r->public_identity.s);
+
+        create_notification = 0;
 
         if (s->expires > act_time) {
             subscription_state.s = (char*) pkg_malloc(32 * sizeof (char*));
@@ -1527,23 +1532,16 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity
             if (contact_match(watcher_contact, &s->watcher_contact) &&
                     (presentity_uri->len == s->presentity_uri.len) && (memcmp(s->presentity_uri.s, presentity_uri->s, presentity_uri->len) == 0)) {
                 LM_DBG("This is a fix to ensure that we only send full reg info XML to the UE that just subscribed.\n");
-                LM_DBG("About to make new notification! We always increment the local cseq and version before we send a new notification\n");
-
-                local_cseq = s->local_cseq + 1;
-                version = s->version + 1;
-                ul.update_subscriber(r, &s, 0, &local_cseq, &version);
-
-                n = new_notification(subscription_state, content_type, &impus, num_impus, s, &explit_dereg_contact, num_explit_dereg_contact);
-                if (n) {
-                    n->_d = _t;
-                    LM_DBG("Notification exists - about to add it\n");
-                    add_notification(n);
-                } else {
-                    LM_DBG("Notification does not exist\n");
-                }
+                create_notification = 1;
             }
         } else {
-
+            if (event_type == IMS_REGISTRAR_CONTACT_REGISTERED) {
+                if(contact_match(contact_uri, &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)) {
+                    LM_DBG("This is a fix to ensure that we only send full reg info XML to the UE that just subscribed.\n");
+                    create_notification = 1;
+                }
+            } 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) */
@@ -1552,6 +1550,12 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity
             //                //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 {
+            //            }
+                               create_notification = 1;
+                       }
+        }
+
+        if(create_notification) {
             LM_DBG("About to make new notification! We always increment the local cseq and version before we send a new notification\n");
 
             local_cseq = s->local_cseq + 1;
@@ -1563,12 +1567,11 @@ void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity
                 n->_d = _t;
                 LM_DBG("Notification exists - about to add it\n");
                 add_notification(n);
-
             } else {
                 LM_DBG("Notification does not exist\n");
             }
-            //            }
         }
+
         s = s->next;
 
         if (subscription_state.s) {
index ac4a3b5..eb1e759 100644 (file)
@@ -132,14 +132,16 @@ 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, int event_type, str *presentity_uri, str *watcher_contact, str *explit_dereg_contact, int num_explit_dereg_contact);
+int event_reg(udomain_t* _d, impurecord_t* r_passed, int event_type, str *presentity_uri, str *watcher_contact, str *contact_uri,
+                str *explit_dereg_contact, int num_explit_dereg_contact);
 
 
 str generate_reginfo_full(udomain_t* _t, str* impu_list, int new_subscription, str *explit_dereg_contact, str* watcher_contact, int num_explit_dereg_contact, unsigned int reginfo_version);
 
 str get_reginfo_partial(impurecord_t *r, ucontact_t *c, int event_type, unsigned int reginfo_version);
 
-void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact);
+void create_notifications(udomain_t* _t, impurecord_t* r_passed, str *presentity_uri, str *watcher_contact, str *contact_uri,
+                            str* impus, int num_impus, int event_type, str *explit_dereg_contact, int num_explit_dereg_contact);
 
 void notification_event_process();
 
index 1619d57..a0ffa35 100644 (file)
@@ -39,6 +39,7 @@
 #include "../../core/parser/msg_parser.h"
 #include "../../core/parser/contact/contact.h"
 #include "../../core/parser/parse_supported.h"
+#include "../../core/parser/contact/parse_contact.h"
 #include "../../core/data_lump_rpl.h"
 #include "../ims_usrloc_scscf/usrloc.h"
 #include "rerrno.h"
@@ -424,13 +425,16 @@ int build_expired_contact(contact_t* chi, contact_for_header_t** contact_header)
 
 //We use shared memory for this so we can use it when we use async diameter
 
-int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header) {
+int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header, struct sip_msg* msg) {
     char *p, *cp;
     int fl, len, expires, expires_orig;
     ucontact_t* c;
     param_t* tmp;
     *contact_header = 0;
        impu_contact_t *impucontact;
+    struct hdr_field* h;
+    contact_t* chi; //contact header information
+    int contact_match = 1;
 
     contact_for_header_t* tmp_contact_header = shm_malloc(sizeof (contact_for_header_t));
     if (!tmp_contact_header) {
@@ -455,80 +459,96 @@ int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header)
         while (impucontact) {
                        c = impucontact->contact;
             if (VALID_CONTACT(c, act_time)) {
-                if (fl) {
-                    memcpy(p, CONTACT_SEP, CONTACT_SEP_LEN);
-                    p += CONTACT_SEP_LEN;
-                } else {
-                    fl = 1;
+                if (msg) {
+                    contact_match = 0;
+                    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) {
+                                if ((c->c.len == chi->uri.len) && !memcmp(c->c.s, chi->uri.s, c->c.len)) {
+                                    contact_match = 1;
+                                    break;
+                                }
+                            }
+                        }
+                    }
                 }
 
-                *p++ = '<';
-                memcpy(p, c->c.s, c->c.len);
-                p += c->c.len;
-                *p++ = '>';
+                if (contact_match) {
+                    if (fl) {
+                        memcpy(p, CONTACT_SEP, CONTACT_SEP_LEN);
+                        p += CONTACT_SEP_LEN;
+                    } else {
+                        fl = 1;
+                    }
 
-                len = len_q(c->q);
-                if (len) {
-                    memcpy(p, Q_PARAM, Q_PARAM_LEN);
-                    p += Q_PARAM_LEN;
-                    memcpy(p, q2str(c->q, 0), len);
-                    p += len;
-                }
+                    *p++ = '<';
+                    memcpy(p, c->c.s, c->c.len);
+                    p += c->c.len;
+                    *p++ = '>';
+
+                    len = len_q(c->q);
+                    if (len) {
+                        memcpy(p, Q_PARAM, Q_PARAM_LEN);
+                        p += Q_PARAM_LEN;
+                        memcpy(p, q2str(c->q, 0), len);
+                        p += len;
+                    }
 
-                memcpy(p, EXPIRES_PARAM, EXPIRES_PARAM_LEN);
-                p += EXPIRES_PARAM_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;
-    
-                if (c->received.s) {
-                    *p++ = ';';
-                    memcpy(p, rcv_param.s, rcv_param.len);
-                    p += rcv_param.len;
-                    *p++ = '=';
-                    *p++ = '\"';
-                    memcpy(p, c->received.s, c->received.len);
-                    p += c->received.len;
-                    *p++ = '\"';
-                }
-                
-                /* put in the rest of the params except Q and received */
-                tmp = c->params;
-                while (tmp) {
-                                       if (tmp->name.len>0 && tmp->name.s) {
-                                               if ((tmp->name.s[0] == 'R' || tmp->name.s[0]=='r') && tmp->name.len == 8 && !memcmp(tmp->name.s+1, "eceived", 7)) {
-                                                       tmp = tmp->next;
-                                                       continue;
-                                               }
-                                               if ((tmp->name.s[0] == 'Q' || tmp->name.s[0]=='q') && tmp->name.len == 1) {
-                                                       tmp = tmp->next;
-                                                       continue;
-                                               }
-                                               if ((tmp->name.s[0] == 'E' || tmp->name.s[0]=='e') && tmp->name.len == 7 && !memcmp(tmp->name.s+1, "xpires", 6)) {
-                                                       tmp = tmp->next;
-                                                       continue;
-                                               }
-                                               *p++ = ';';
-                                               memcpy(p, tmp->name.s, tmp->name.len);
-                                               p += tmp->name.len;
-                                       }
+                    memcpy(p, EXPIRES_PARAM, EXPIRES_PARAM_LEN);
+                    p += EXPIRES_PARAM_LEN;
                     
-                    if (tmp->body.len > 0) {
+                    /* 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;
+
+                    if (c->received.s) {
+                        *p++ = ';';
+                        memcpy(p, rcv_param.s, rcv_param.len);
+                        p += rcv_param.len;
                         *p++ = '=';
                         *p++ = '\"';
-                        memcpy(p, tmp->body.s, tmp->body.len);
-                        p += tmp->body.len;
+                        memcpy(p, c->received.s, c->received.len);
+                        p += c->received.len;
                         *p++ = '\"';
                     }
-                    tmp = tmp->next;
+                    
+                    /* put in the rest of the params except Q and received */
+                    tmp = c->params;
+                    while (tmp) {
+                        if (tmp->name.len>0 && tmp->name.s) {
+                            if ((tmp->name.s[0] == 'R' || tmp->name.s[0]=='r') && tmp->name.len == 8 && !memcmp(tmp->name.s+1, "eceived", 7)) {
+                                tmp = tmp->next;
+                                continue;
+                            }
+                            if ((tmp->name.s[0] == 'Q' || tmp->name.s[0]=='q') && tmp->name.len == 1) {
+                                tmp = tmp->next;
+                                continue;
+                            }
+                            if ((tmp->name.s[0] == 'E' || tmp->name.s[0]=='e') && tmp->name.len == 7 && !memcmp(tmp->name.s+1, "xpires", 6)) {
+                                tmp = tmp->next;
+                                continue;
+                            }
+                            *p++ = ';';
+                            memcpy(p, tmp->name.s, tmp->name.len);
+                            p += tmp->name.len;
+                        }
+                        
+                        if (tmp->body.len > 0) {
+                            *p++ = '=';
+                            *p++ = '\"';
+                            memcpy(p, tmp->body.s, tmp->body.len);
+                            p += tmp->body.len;
+                            *p++ = '\"';
+                        }
+                        tmp = tmp->next;
+                    }
                 }
             }
                        impucontact = impucontact->next;
index 1f2c8f5..d425f3f 100644 (file)
@@ -64,7 +64,7 @@ int reg_send_reply_transactional(struct sip_msg* _m, contact_for_header_t* conta
 /*! \brief
  * Build Contact HF for reply
  */
-int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header);
+int build_contact(impurecord_t* impurec, contact_for_header_t** contact_header, struct sip_msg* msg);
 int build_expired_contact(contact_t* chi, contact_for_header_t** contact_header); //this is for building the expired response - ie reply to dereg
 
 int build_p_associated_uri(ims_subscription* s);
index 43dfd47..9f7dac9 100644 (file)
@@ -159,7 +159,7 @@ static inline int star(udomain_t* _d, str* _a) {
 
         if (ul.get_impurecord(_d, _a, &r) == 0) {
             contact_for_header_t** contact_header = 0;
-            build_contact(r, contact_header);
+            build_contact(r, contact_header, 0);
             free_contact_buf(*contact_header);
             ul.unlock_udomain(_d, _a);
         }
@@ -828,9 +828,19 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                 goto error;
             }
             //now build the contact buffer to be include in the reply message and unlock
-            build_contact(impu_rec, contact_header);
+            build_contact(impu_rec, contact_header, 0);
             build_p_associated_uri(*s);
-            notify_subscribers(impu_rec, 0, 0, IMS_REGISTRAR_CONTACT_REGISTERED);
+
+
+            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) {
+                        event_reg(0, impu_rec, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0, &chi->uri, 0, 0);
+                    }
+                }
+            }
+
+
             ul.unlock_udomain(_d, public_identity);
             break;
         case AVP_IMS_SAR_RE_REGISTRATION:
@@ -851,8 +861,8 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                 ul.unlock_udomain(_d, public_identity);
                 goto error;
             }
-            //build the contact buffer for all registered contacts on explicit IMPU
-            build_contact(impu_rec, contact_header);
+            //build the contact buffer for the exact registered contact for reply on explicit IMPU
+            build_contact(impu_rec, contact_header, msg);
             build_p_associated_uri(impu_rec->s);
 
             subscription = impu_rec->s;
@@ -863,7 +873,7 @@ int update_contacts(struct sip_msg* msg, udomain_t* _d,
                         ecf1, ecf2, &impu_rec) != 0) {
                     LM_ERR("Unable to update explicit impurecord for <%.*s>\n", public_identity->len, public_identity->s);
                 }
-                build_contact(impu_rec, contact_header);
+                build_contact(impu_rec, contact_header, msg);
                 ul.unlock_udomain(_d, public_identity);
                 break;
             }
@@ -913,7 +923,15 @@ 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, 0, 0, IMS_REGISTRAR_CONTACT_REGISTERED);
+
+            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) {
+                        event_reg(0, impu_rec, IMS_REGISTRAR_CONTACT_REGISTERED, 0, 0, &chi->uri, 0, 0);
+                    }
+                }
+            }
+
            ul.unlock_udomain(_d, public_identity);
             break;
         case AVP_IMS_SAR_USER_DEREGISTRATION:
index 25e82f3..13dcde5 100644 (file)
@@ -94,6 +94,6 @@ void ul_contact_changed(impurecord_t* r, ucontact_t* c, int type, void* param) {
 //    
     if (type == UL_IMPU_DELETE_CONTACT) {
         LM_DBG("Received notification of UL CONTACT DELETE\n");
-        event_reg(0, r, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0, 0, 0);
+        event_reg(0, r, IMS_REGISTRAR_CONTACT_UNREGISTERED, 0, 0, 0, 0, 0);
     }
 }