Pārlūkot izejas kodu

modules/ims_qos: second iteration of ims_qos module
- module now support media authorization over Diameter Rx (between P-CSCF and PCRF)

Richard Good 12 gadi atpakaļ
vecāks
revīzija
324e458ad6

+ 31 - 34
modules/ims_qos/cdpeventprocessor.c

@@ -200,40 +200,37 @@ void cdp_cb_event_process() {
         switch (ev->event) {
             case AUTH_EV_SESSION_TIMEOUT:
             case AUTH_EV_SESSION_GRACE_TIMEOUT:
-            case AUTH_EV_SESSION_LIFETIME_TIMEOUT:
-                LM_DBG("Rx CDP Session: AUTH EV SESSION TIMEOUT or GRACE TIMEOUT or LIFE TIMEOUT\n");
+            case AUTH_EV_RECV_ASR:
+                LM_DBG("Received notification of ASR from transport plane or CDP timeout for CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                        " and domain [%.*s]\n",
+                        rx_session_id->len, rx_session_id->s,
+                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                        p_session_data->domain.len, p_session_data->domain.s);
+
 
                 if (p_session_data->subscribed_to_signaling_path_status) {
-                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a subscription to signalling bearer session");
+                    //nothing to do here - just wait for AUTH_EV_SERVICE_TERMINATED event
                 } else {
-                    LM_DBG("Received notification of CDP timeout of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a media bearer session session");
+                    //this is a media bearer session that was terminated from the transport plane - we need to terminate the associated dialog
+                    //so we set p_session_data->must_terminate_dialog to 1 and when we receive AUTH_EV_SERVICE_TERMINATED event we will terminate the dialog
+                    p_session_data->must_terminate_dialog = 1;
                 }
                 break;
 
             case AUTH_EV_SERVICE_TERMINATED:
-                LM_DBG("Rx CDP Session: Service terminated\n");
-                
+                LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
+                        " and domain [%.*s]\n",
+                        rx_session_id->len, rx_session_id->s,
+                        p_session_data->registration_aor.len, p_session_data->registration_aor.s,
+                        p_session_data->domain.len, p_session_data->domain.s);
+
                 if (p_session_data->subscribed_to_signaling_path_status) {
-                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a subscription to signalling bearer session");
-                    
                     //instead of removing the contact from usrloc_pcscf we just change the state of the contact to TERMINATE_PENDING_NOTIFY
                     //pcscf_registrar sees this, sends a SIP PUBLISH and on SIP NOTIFY the contact is deleted
-                    
+
                     if (ul.register_udomain(p_session_data->domain.s, &domain)
                             < 0) {
                         LM_DBG("Unable to register usrloc domain....aborting\n");
@@ -251,21 +248,21 @@ void cdp_cb_event_process() {
                     }
                     ul.unlock_udomain(domain, &p_session_data->registration_aor);
                 } else {
-                    LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]"
-                            " and domain [%.*s]\n",
-                            rx_session_id->len, rx_session_id->s,
-                            p_session_data->registration_aor.len, p_session_data->registration_aor.s,
-                            p_session_data->domain.len, p_session_data->domain.s);
                     LM_DBG("This is a media bearer session session");
-                    LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
-                            p_session_data->callid.len, p_session_data->callid.s,
-                            p_session_data->ftag.len, p_session_data->ftag.s,
-                            p_session_data->ttag.len, p_session_data->ttag.s);
-                    dlgb.terminate_dlg(&p_session_data->callid,
-                            &p_session_data->ftag, &p_session_data->ttag, NULL,
-                            &release_reason);
+                    
+                    //we only terminate the dialog if this was triggered from the transport plane or timeout - i.e. if must_terminate_dialog is set
+                    //if this was triggered from the signalling plane (i.e. someone hanging up) then we don'y need to terminate the dialog
+                    if (p_session_data->must_terminate_dialog) {
+                        LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n",
+                                p_session_data->callid.len, p_session_data->callid.s,
+                                p_session_data->ftag.len, p_session_data->ftag.s,
+                                p_session_data->ttag.len, p_session_data->ttag.s);
+                        dlgb.terminate_dlg(&p_session_data->callid,
+                                &p_session_data->ftag, &p_session_data->ttag, NULL,
+                                &release_reason);
+                    }
                 }
-                
+
                 //free callback data
                 if (p_session_data) {
                     shm_free(p_session_data);

+ 29 - 19
modules/ims_qos/doc/ims_qos_admin.xml

@@ -193,7 +193,7 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
     <section>
       <title><function
-      moreinfo="none">Rx_AAR_Register(domain)</function></title>
+      moreinfo="none">Rx_AAR_Register(route_block, domain)</function></title>
 
       <para>Perform a AAR on Diameter RX interface to subscribe to signalling 
       status. This purpose of this is tell a Diameter server (typically a PCRF)
@@ -204,6 +204,9 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
       <para>Meaning of the parameters is as follows:</para>
 
       <itemizedlist>
+        <listitem>
+          <para>Route block to resume after async UAR Diameter reply.</para>
+        </listitem>
         <listitem>
           <para><emphasis>domain</emphasis> that usrloc_pcscf uses to store 
           user information.</para>
@@ -220,8 +223,12 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
         <programlisting format="linespecific">
 ...
-    Rx_AAR_Register("location");
-    
+if(Rx_AAR_Register("REG_AAR_REPLY","location")==0){
+    exit;
+}
+...
+route[REG_AAR_REPLY]
+{
     switch ($avp(s:aar_return_code)) {
         case 1:
             xlog("L_DBG", "Diameter: AAR success on subscription to signalling\n");
@@ -231,7 +238,6 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
             t_reply("403", "Can't register to QoS for signalling");
             exit;
     }
-
 ...
 </programlisting>
       </example>
@@ -239,7 +245,7 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
     
     <section>
       <title><function
-      moreinfo="none">Rx_AAR(domain)</function></title>
+      moreinfo="none">Rx_AAR(route_block, direction)</function></title>
 
       <para>Perform a AAR on Diameter RX interface to request resource 
       authorisation from a Diameter server (typically a PCRF). For more details 
@@ -249,8 +255,11 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
       <itemizedlist>
         <listitem>
-          <para><emphasis>domain</emphasis> that usrloc_pcscf uses to store 
-          user information.</para>
+          <para>Route block to resume after async UAR Diameter reply.</para>
+        </listitem>
+        <listitem>
+          <para><emphasis>direction</emphasis>the direction of this message - 
+          orig, term, etc.</para>
         </listitem>
       </itemizedlist>
 
@@ -264,18 +273,19 @@ modparam("ims_qos", "cdp_event_latency_log", 1)
 
         <programlisting format="linespecific">
 ...
-    Rx_AAR("location");
-    
-    switch ($avp(s:aar_return_code)) {
-        case 1:
-            xlog("L_DBG", "Diameter: AAR success\n");
-            break;
-        default:
-            xlog("L_ERR", "Diameter: AAR failed\n");
-            t_reply("403", "QoS not authorized");
-            exit;
-    }
-
+if(Rx_AAR("ORIG_SESSION_AAR_REPLY","orig")==0){
+    exit;
+}
+...
+route[ORIGN_SESSION_AAR_REPLY]
+{
+    if ($avp(s:aar_return_code) != 1) {
+        xlog("L_ERR", "IMS: AAR failed Orig\n");
+        dlg_terminate("all", "Sorry no QoS available");
+    } else {
+        xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n");
+    } 
+}
 ...
 </programlisting>
       </example>

+ 314 - 204
modules/ims_qos/mod.c

@@ -75,7 +75,7 @@
 
 MODULE_VERSION
 
-extern gen_lock_t* process_lock; /* lock on the process table */
+        extern gen_lock_t* process_lock; /* lock on the process table */
 
 str orig_session_key = {"originating", 11};
 str term_session_key = {"terminating", 11};
@@ -101,8 +101,7 @@ static int mod_child_init(int);
 static void mod_destroy(void);
 
 static int fixup_aar_register(void** param, int param_no);
-
-static void free_dialog_data(void *data);
+static int fixup_aar(void** param, int param_no);
 
 int * callback_singleton; /*< Callback singleton */
 
@@ -114,12 +113,12 @@ char* rx_forced_peer_s = "";
 str rx_forced_peer;
 
 /* commands wrappers and fixups */
-static int w_rx_aar(struct sip_msg *msg, char* direction, char *bar);
-static int w_rx_aar_register(struct sip_msg *msg, char* str1, char *bar);
+static int w_rx_aar(struct sip_msg *msg, char *route, char* direction, char *bar);
+static int w_rx_aar_register(struct sip_msg *msg, char *route, char* str1, char *bar);
 
 static cmd_export_t cmds[] = {
-    { "Rx_AAR", (cmd_function) w_rx_aar, 1, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
-    { "Rx_AAR_Register", (cmd_function) w_rx_aar_register, 1, fixup_aar_register, 0, REQUEST_ROUTE},
+    { "Rx_AAR", (cmd_function) w_rx_aar, 2, fixup_aar, 0, REQUEST_ROUTE | ONREPLY_ROUTE},
+    { "Rx_AAR_Register", (cmd_function) w_rx_aar_register, 2, fixup_aar_register, 0, REQUEST_ROUTE},
     { 0, 0, 0, 0, 0, 0}
 };
 
@@ -134,9 +133,9 @@ static param_export_t params[] = {
 };
 
 stat_export_t mod_stats[] = {
-	{"aar_avg_response_time" ,  STAT_IS_FUNC, 	(stat_var**)get_avg_aar_response_time	},
-	{"aar_timeouts" ,  			0, 				(stat_var**)&stat_aar_timeouts  		},
-	{0,0,0}
+    {"aar_avg_response_time", STAT_IS_FUNC, (stat_var**) get_avg_aar_response_time},
+    {"aar_timeouts", 0, (stat_var**) & stat_aar_timeouts},
+    {0, 0, 0}
 };
 
 /** module exports */
@@ -156,7 +155,7 @@ int fix_parameters() {
     rx_forced_peer.s = rx_forced_peer_s;
     rx_forced_peer.len = strlen(rx_forced_peer_s);
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -169,16 +168,16 @@ static int mod_init(void) {
         goto error;
 
 #ifdef STATISTICS
-	/* register statistics */
-	if (register_module_stats( exports.name, mod_stats)!=0 ) {
-		LM_ERR("failed to register core statistics\n");
-		goto error;
-	}
-
-	if (!register_stats()){
-		LM_ERR("Unable to register statistics\n");
-		goto error;
-	}
+    /* register statistics */
+    if (register_module_stats(exports.name, mod_stats) != 0) {
+        LM_ERR("failed to register core statistics\n");
+        goto error;
+    }
+
+    if (!register_stats()) {
+        LM_ERR("Unable to register statistics\n");
+        goto error;
+    }
 #endif
 
     callback_singleton = shm_malloc(sizeof (int));
@@ -216,12 +215,12 @@ static int mod_init(void) {
     bind_usrloc = (bind_usrloc_t) find_export("ul_bind_ims_usrloc_pcscf", 1, 0);
     if (!bind_usrloc) {
         LM_ERR("can't bind usrloc_pcscf\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (bind_usrloc(&ul) < 0) {
         LM_ERR("can't bind to usrloc pcscf\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
     LM_DBG("Successfully bound to PCSCF Usrloc module\n");
 
@@ -236,7 +235,7 @@ static int mod_init(void) {
     return 0;
 error:
     LM_ERR("Failed to initialise ims_qos module\n");
-    return RX_RETURN_FALSE;
+    return CSCF_RETURN_FALSE;
 }
 
 /**
@@ -294,7 +293,7 @@ void callback_for_cdp_session(int event, void *session) {
     //only put the events we care about on the event stack
     if (event == AUTH_EV_SESSION_TIMEOUT ||
             event == AUTH_EV_SESSION_GRACE_TIMEOUT ||
-            event == AUTH_EV_SESSION_LIFETIME_TIMEOUT ||
+            event == AUTH_EV_RECV_ASR ||
             event == AUTH_EV_SERVICE_TERMINATED) {
 
         LOG(L_DBG, "callback_for_cdp session(): called with event %d and session id [%.*s]\n", event, rx_session_id->len, rx_session_id->s);
@@ -349,19 +348,6 @@ AAAMessage* callback_cdp_request(AAAMessage *request, void *param) {
     return 0;
 }
 
-static void free_dialog_data(void *data) {
-    str *rx_session_id = (str*) data;
-    if (rx_session_id) {
-        if (rx_session_id->s) {
-            shm_free(rx_session_id->s);
-            rx_session_id->s = 0;
-        }
-        shm_free(rx_session_id);
-        rx_session_id = 0;
-    }
-
-}
-
 void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
     LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
 
@@ -405,28 +391,56 @@ void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
 /* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register
  * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish)
  */
-static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
+static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
+
+    int ret = CSCF_RETURN_ERROR;
     struct cell *t;
-    AAAMessage* resp;
+
     AAASession* auth_session;
     rx_authsessiondata_t* rx_authdata_p = 0;
-    unsigned int result = AAA_SUCCESS;
     str *rx_session_id;
     str callid = {0, 0};
     str ftag = {0, 0};
     str ttag = {0, 0};
+    
+    str route_name;
+
+    cfg_action_t* cfg_action = 0;
+    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
+    char* direction = str1;
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+
+    LM_DBG("Rx AAR called\n");
+    //create the default return code AVP
+    create_return_code(ret);
 
     //We don't ever do AAR on request for calling scenario...
     if (msg->first_line.type != SIP_REPLY) {
         LM_DBG("Can't do AAR for call session in request\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
 
     //is it appropriate to send AAR at this stage?
     t = tmb.t_gett();
-    if (!t) {
+    if (t == NULL || t == T_UNDEFINED) {
         LM_WARN("Cannot get transaction for AAR based on SIP Request\n");
-        goto aarna;
+        //goto aarna;
+        return CSCF_RETURN_ERROR;
     }
 
     //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK!
@@ -435,34 +449,85 @@ static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
             || memcmp(t->method.s, "UPDATE", 6) == 0))) {
         if (cscf_get_content_length(msg) == 0
                 || cscf_get_content_length(t->uas.request) == 0) {
-            goto aarna; //AAR na if we dont have offer/answer pair
+            LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR");
+            //goto aarna; //AAR na if we dont have offer/answer pair
+            return CSCF_RETURN_ERROR;
         }
     } else {
-        goto aarna;
+        LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR");
+        return CSCF_RETURN_ERROR;
     }
 
     /* get callid, from and to tags to be able to identify dialog */
     callid = cscf_get_call_id(msg, 0);
     if (callid.len <= 0 || !callid.s) {
         LM_ERR("unable to get callid\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
     if (!cscf_get_from_tag(msg, &ftag)) {
         LM_ERR("Unable to get ftag\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
     if (!cscf_get_to_tag(msg, &ttag)) {
         LM_ERR("Unable to get ttag\n");
-        goto error;
+        return CSCF_RETURN_ERROR;
     }
 
     //check to see that this is not a result of a retransmission in reply route only
     if (msg->cseq == NULL
             && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) {
         LM_ERR("No Cseq header found - aborting\n");
-        goto error;
-    }
-
+        return CSCF_RETURN_ERROR;
+    }
+
+    saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t));
+    if (!saved_t_data) {
+        LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data, 0, sizeof (saved_transaction_t));
+    saved_t_data->act = cfg_action;
+    //OTHER parms need after async response set here
+    //store call id
+    saved_t_data->callid.s = (char*) shm_malloc(callid.len + 1);
+    if (!saved_t_data->callid.s) {
+        LM_ERR("no more memory trying to save transaction state : callid\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->callid.s, 0, callid.len + 1);
+    memcpy(saved_t_data->callid.s, callid.s, callid.len);
+    saved_t_data->callid.len = callid.len;
+
+    //store ttag
+    saved_t_data->ttag.s = (char*) shm_malloc(ttag.len + 1);
+    if (!saved_t_data->ttag.s) {
+        LM_ERR("no more memory trying to save transaction state : ttag\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->ttag.s, 0, ttag.len + 1);
+    memcpy(saved_t_data->ttag.s, ttag.s, ttag.len);
+    saved_t_data->ttag.len = ttag.len;
+
+    //store ftag
+    saved_t_data->ftag.s = (char*) shm_malloc(ftag.len + 1);
+    if (!saved_t_data->ftag.s) {
+        LM_ERR("no more memory trying to save transaction state : ftag\n");
+        shm_free(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data->ftag.s, 0, ftag.len + 1);
+    memcpy(saved_t_data->ftag.s, ftag.s, ftag.len);
+    saved_t_data->ftag.len = ftag.len;
+
+    //store branch
+    int branch;
+    if (tmb.t_check( msg  , &branch )==-1){
+        LOG(L_ERR, "ERROR: t_suspend: failed find UAC branch\n");
+        return CSCF_RETURN_ERROR;
+    }
+    
     //Check that we dont already have an auth session for this specific dialog
     //if not we create a new one and attach it to the dialog (via session ID).
     enum dialog_direction dlg_direction = get_dialog_direction(direction);
@@ -504,62 +569,44 @@ static int w_rx_aar(struct sip_msg *msg, char* direction, char* bar) {
         LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction);
     } else {
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
-        //TODO - what to do on updates - reinvites, etc
-        goto aarna; //TODO: for now we ignore
+        if (saved_t_data)
+                free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+        create_return_code(CSCF_RETURN_TRUE);
+        return CSCF_RETURN_TRUE;
     }
 
-    resp = rx_send_aar(t->uas.request, msg, auth_session, &callid, &ftag, &ttag,
-            direction, &rx_authdata_p);
-
-    if (!resp) {
-        LM_ERR("No response received for AAR request\n");
-        goto error;
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_transaction_global_data(saved_t_data);
+        return CSCF_RETURN_ERROR;
     }
 
-    if (!rx_authdata_p) {
-        LM_ERR("Rx: mod.c: error creating new rx_auth_data\n");
-        goto error;
-    }
-    //
-    //    /* Process the response to AAR, retrieving result code and associated Rx session ID */
-    if (rx_process_aaa(resp, &result) < 0) {
-        LM_DBG("Failed to process AAA from PCRF\n");
-        cdpb.AAAFreeMessage(&resp);
-        goto error;
-    }
-    cdpb.AAAFreeMessage(&resp);
-
+    LM_DBG("Sending Rx AAR");
+    ret = rx_send_aar(t->uas.request, msg, auth_session, direction, saved_t_data);
 
-    if (result >= 2000 && result < 3000) {
-        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", result);
-
-        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+    if (!ret) {
+        LM_ERR("Failed to send AAR\n");
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        goto error;
 
-        passed_rx_session_id->s = 0;
-        passed_rx_session_id->len = 0;
-        STR_SHM_DUP(*passed_rx_session_id, auth_session->id, "cb_passed_rx_session_id");
 
-        LM_DBG("passed rx session id %.*s", passed_rx_session_id->len, passed_rx_session_id->s);
+    } else {
+        LM_DBG("Successful async send of AAR\n");
+        return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
+    }
 
-        dlgb.register_dlgcb_nodlg(&callid, &ftag, &ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+error:
+    LM_ERR("Error trying to send AAR (calling)\n");
+    if (saved_t_data)
+        free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+    //otherwise the callback will segfault
 
-        return RX_RETURN_TRUE;
-    } else {
-        LM_DBG("Received negative reply from PCRF for AAR Request\n");
-        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
-        goto error; // if its not a success then that means i want to reject this call!
-    }
-out_of_memory:
-    error :
-            LM_ERR("Error trying to send AAR (calling)\n");
-    return RX_RETURN_FALSE;
-aarna:
-    LM_DBG("Policy and Charging Control non-applicable\n");
-    return RX_RETURN_AAR_NA;
+     return CSCF_RETURN_ERROR;
 }
 
 /* Wrapper to send AAR from config file - only used for registration */
-static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
+static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) {
 
     int ret = CSCF_RETURN_ERROR;
     struct pcontact_info ci;
@@ -571,14 +618,32 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
     AAASession* auth;
     rx_authsessiondata_t* rx_regsession_data_p;
     cfg_action_t* cfg_action = 0;
+    str route_name;
     char* p;
     int aar_sent = 0;
-    saved_transaction_local_t* local_data = 0;		//data to be shared across all async calls
-    saved_transaction_t* saved_t_data = 0;			//data specific to each contact's AAR async call
-    aar_param_t* ap = (aar_param_t*) str1;
-    udomain_t* domain_t = ap->domain;
-    cfg_action = ap->paction->next;
-    int is_rereg = 0;								//is this a reg/re-reg
+    saved_transaction_local_t* local_data = 0; //data to be shared across all async calls
+    saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call
+    
+    if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+    
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    
+    udomain_t* domain_t = (udomain_t*) str1;
+    
+    int is_rereg = 0; //is this a reg/re-reg
 
     LM_DBG("Rx AAR Register called\n");
 
@@ -619,60 +684,60 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
             //if ((cscf_get_expires(msg) == 0)) {
             LM_DBG("This is a de registration\n");
             LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n");
-            create_return_code(RX_RETURN_TRUE);
-            return RX_RETURN_TRUE;
+            create_return_code(CSCF_RETURN_TRUE);
+            return CSCF_RETURN_TRUE;
         }
     }
 
     //before we continue, make sure we have a transaction to work with (viz. cdp async)
-	t = tmb.t_gett();
-	if (t == NULL || t == T_UNDEFINED) {
-		if (tmb.t_newtran(msg) < 0) {
-			LM_ERR("cannot create the transaction for UAR async\n");
-			return CSCF_RETURN_ERROR;
-		}
-		t = tmb.t_gett();
-		if (t == NULL || t == T_UNDEFINED) {
-			LM_ERR("cannot lookup the transaction\n");
-			return CSCF_RETURN_ERROR;
-		}
-	}
-
-	saved_t_data = (saved_transaction_t*)shm_malloc(sizeof(saved_transaction_t));
-	if (!saved_t_data){
-		LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
-		return CSCF_RETURN_ERROR;
-	}
-	memset(saved_t_data,0,sizeof(saved_transaction_t));
-	saved_t_data->act = cfg_action;
-	saved_t_data->domain = domain_t;
-	saved_t_data->lock = lock_alloc();
-	if (saved_t_data->lock == NULL) {
-		LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
-		return CSCF_RETURN_ERROR;
-	}
-	if (lock_init(saved_t_data->lock) == NULL) {
-		LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
-		return CSCF_RETURN_ERROR;
-	}
-
-	LM_DBG("Suspending SIP TM transaction\n");
-	if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
-		LM_ERR("failed to suspend the TM processing\n");
-		free_saved_transaction_global_data(saved_t_data);
-		return CSCF_RETURN_ERROR;
-	}
-
-	LM_DBG("Successfully suspended transaction\n");
-
-	//now get the contacts in the REGISTER and do AAR for each one.
+    t = tmb.t_gett();
+    if (t == NULL || t == T_UNDEFINED) {
+        if (tmb.t_newtran(msg) < 0) {
+            LM_ERR("cannot create the transaction for UAR async\n");
+            return CSCF_RETURN_ERROR;
+        }
+        t = tmb.t_gett();
+        if (t == NULL || t == T_UNDEFINED) {
+            LM_ERR("cannot lookup the transaction\n");
+            return CSCF_RETURN_ERROR;
+        }
+    }
+
+    saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t));
+    if (!saved_t_data) {
+        LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n");
+        return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t_data, 0, sizeof (saved_transaction_t));
+    saved_t_data->act = cfg_action;
+    saved_t_data->domain = domain_t;
+    saved_t_data->lock = lock_alloc();
+    if (saved_t_data->lock == NULL) {
+        LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n");
+        return CSCF_RETURN_ERROR;
+    }
+    if (lock_init(saved_t_data->lock) == NULL) {
+        LM_ERR("unable to init lock for saved_t_transaction reply counter\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_transaction_global_data(saved_t_data);
+        return CSCF_RETURN_ERROR;
+    }
+
+    LM_DBG("Successfully suspended transaction\n");
+
+    //now get the contacts in the REGISTER and do AAR for each one.
     cb = cscf_parse_contacts(msg);
     if (!cb || (!cb->contacts && !cb->star)) {
         LM_DBG("No contact headers in Register message\n");
         goto error;
     }
 
-    lock_get(saved_t_data->lock);		//we lock here to make sure we send all requests before processing replies asynchronously
+    lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously
     for (h = msg->contact; h; h = h->next) {
         if (h->type == HDR_CONTACT_T && h->parsed) {
             for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) {
@@ -685,7 +750,7 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                 } else if (pcontact->reg_state == PCONTACT_REG_PENDING
                         || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request
                     LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n"
-                    		, pcontact->aor.len, pcontact->aor.s);
+                            , pcontact->aor.len, pcontact->aor.s);
 
                     //get IP address from contact
                     struct sip_uri puri;
@@ -745,12 +810,12 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                     }
 
                     //we are ready to send the AAR async. lets save the local data data
-                    int local_data_len = sizeof(saved_transaction_local_t) + c->uri.len + auth->id.len;
+                    int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len;
                     local_data = shm_malloc(local_data_len);
                     if (!local_data) {
-                    	LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
-                    	lock_release(saved_t_data->lock);
-                    	goto error;
+                        LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n");
+                        lock_release(saved_t_data->lock);
+                        goto error;
                     }
                     memset(local_data, 0, local_data_len);
 
@@ -761,32 +826,36 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                     local_data->contact.s = p;
                     local_data->contact.len = c->uri.len;
                     memcpy(p, c->uri.s, c->uri.len);
-                    p+=c->uri.len;
+                    p += c->uri.len;
 
                     local_data->auth_session_id.s = p;
                     local_data->auth_session_id.len = auth->id.len;
                     memcpy(p, auth->id.s, auth->id.len);
-                    p+=auth->id.len;
+                    p += auth->id.len;
 
-                    if (p!=( ((char*)local_data) + local_data_len) ) {
-                    	LM_CRIT("buffer overflow\n");
-                    	free_saved_transaction_data(local_data);
-                    	goto error;
+                    if (p != (((char*) local_data) + local_data_len)) {
+                        LM_CRIT("buffer overflow\n");
+                        free_saved_transaction_data(local_data);
+                        goto error;
                     }
 
                     LM_DBG("Calling send aar register");
-                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
+
+                    //TODOD remove - no longer user AOR parm
+                    //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object
+                    ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object
+
                     ul.unlock_udomain(domain_t, &c->uri);
 
                     if (!ret) {
-                    	LM_ERR("Failed to send AAR\n");
-                    	lock_release(saved_t_data->lock);
-                    	free_saved_transaction_data(local_data);	//free the local data becuase the CDP async request was not successful (we must free here)
-                    	goto error;
+                        LM_ERR("Failed to send AAR\n");
+                        lock_release(saved_t_data->lock);
+                        free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here)
+                        goto error;
                     } else {
-                    	aar_sent = 1;
-                    	//before we send - bump up the reply counter
-			saved_t_data->answers_not_received++;		//we dont need to lock as we already hold the lock above
+                        aar_sent = 1;
+                        //before we send - bump up the reply counter
+                        saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above
                     }
                 } else {
                     //contact exists - this is a re-registration, for now we just ignore this
@@ -796,11 +865,11 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
                 }
             }
         } else {
-        	if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
-        		LM_ERR("Failed to parse contact header\n");
-        		lock_release(saved_t_data->lock);
-        		goto error;
-        	}
+            if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error
+                LM_ERR("Failed to parse contact header\n");
+                lock_release(saved_t_data->lock);
+                goto error;
+            }
         }
     }
     //all requests sent at this point - we can unlock the reply lock
@@ -811,46 +880,87 @@ static int w_rx_aar_register(struct sip_msg *msg, char* str1, char* bar) {
      * 2. haven't needed to send ANY AAR's for ANY contacts
      */
     if (aar_sent) {
-    	LM_DBG("Successful async send of AAR\n");
-    	return RX_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
+        LM_DBG("Successful async send of AAR\n");
+        return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process
     } else {
-    	create_return_code(RX_RETURN_TRUE);
-    	free_saved_transaction_global_data(saved_t_data);	//no aar sent so we must free the global data
-    	return RX_RETURN_TRUE;
+        create_return_code(CSCF_RETURN_TRUE);
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        if (saved_t_data) {
+            free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data
+        }
+        //return CSCF_RETURN_ERROR;
+        return CSCF_RETURN_TRUE;
     }
 error:
     LM_ERR("Error trying to send AAR\n");
-    if (!aar_sent)
-    	if (saved_t_data)
-    		free_saved_transaction_global_data(saved_t_data); 	//only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
-    															//otherwise the callback will segfault
-    return RX_RETURN_FALSE;
+    if (!aar_sent) {
+        tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
+        if (saved_t_data) {
+            free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free
+            //otherwise the callback will segfault
+        }
+    }
+    return CSCF_RETURN_ERROR;
+    //return CSCF_RETURN_FALSE;
 }
 
-static int fixup_aar_register(void** param, int param_no)
-{
-	udomain_t* d;
-	aar_param_t *ap;
-
-	if(param_no!=1)
-		return 0;
-	ap = (aar_param_t*)pkg_malloc(sizeof(aar_param_t));
-	if(ap==NULL)
-	{
-		LM_ERR("no more pkg\n");
-		return -1;
-	}
-	memset(ap, 0, sizeof(aar_param_t));
-	ap->paction = get_action_from_param(param, param_no);
-
-	if (ul.register_udomain((char*) *param, &d) < 0) {
-		LM_ERR("failed to register domain\n");
-		return E_UNSPEC;
-	}
-	ap->domain = d;
-
-	*param = (void*)ap;
-	return 0;
+static int fixup_aar_register(void** param, int param_no) {
+//    udomain_t* d;
+//    aar_param_t *ap;
+//
+//    if (param_no != 1)
+//        return 0;
+//    ap = (aar_param_t*) pkg_malloc(sizeof (aar_param_t));
+//    if (ap == NULL) {
+//        LM_ERR("no more pkg\n");
+//        return -1;
+//    }
+//    memset(ap, 0, sizeof (aar_param_t));
+//    ap->paction = get_action_from_param(param, param_no);
+//
+//    if (ul.register_udomain((char*) *param, &d) < 0) {
+//        LM_ERR("failed to register domain\n");
+//        return E_UNSPEC;
+//    }
+//    ap->domain = d;
+//
+//    *param = (void*) ap;
+//    return 0;
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    } else if (param_no == 2) {
+        udomain_t* d;
+
+        if (ul.register_udomain((char*) *param, &d) < 0) {
+            LM_ERR("Error doing fixup on assign save");
+            return -1;
+        }
+        *param = (void*) d;
+    }
+
+    return 0;
+}
+
+static int fixup_aar(void** param, int param_no) {
+    if (strlen((char*) *param) <= 0) {
+        LM_ERR("empty parameter %d not allowed\n", param_no);
+        return -1;
+    }
+
+    if (param_no == 1) {        //route name - static or dynamic string (config vars)
+        if (fixup_spve_null(param, param_no) < 0)
+            return -1;
+        return 0;
+    }
+
+    return 0;
 }
 
 /*create a return code to be passed back into config file*/

+ 0 - 11
modules/ims_qos/mod.h

@@ -49,17 +49,6 @@
 
 #define MOD_NAME "ims_qos"
 
-/** Return and break the execution of routing script */
-#define RX_RETURN_BREAK	0 
-/** Return true in the routing script */
-#define RX_RETURN_TRUE	1
-/** Return positive but indicate AAR not viable and wasnt sent */
-#define RX_RETURN_AAR_NA	2
-/** Return false in the routing script */
-#define RX_RETURN_FALSE -1
-/** Return error in the routing script */
-#define RX_RETURN_ERROR -2
-
 /** callback functions */
 
 struct AAAMessage;

+ 149 - 27
modules/ims_qos/rx_aar.c

@@ -65,6 +65,7 @@
 
 #include "mod.h"
 
+#include "../../lib/ims/useful_defs.h"
 #define macro_name(_rc)	#_rc
 
 //extern struct tm_binds tmb;
@@ -74,7 +75,101 @@ str IMS_Serv_AVP_val = {"IMS Services", 12};
 str IMS_Em_Serv_AVP_val = {"Emergency IMS Call", 18};
 str IMS_Reg_AVP_val = {"IMS Registration", 16};
 
-void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
+static void free_dialog_data(void *data) {
+    str *rx_session_id = (str*) data;
+    if (rx_session_id) {
+        if (rx_session_id->s) {
+            shm_free(rx_session_id->s);
+            rx_session_id->s = 0;
+        }
+        shm_free(rx_session_id);
+        rx_session_id = 0;
+    }
+
+}
+
+void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
+    struct cell *t = 0;
+    unsigned int cdp_result;
+    int result = CSCF_RETURN_ERROR;
+
+    LM_DBG("Received AAR callback\n");
+    saved_transaction_t* data = (saved_transaction_t*) param;
+
+    LM_DBG("received AAA answer");
+
+    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
+        LM_ERR("t_continue: transaction not found\n");
+        goto error;
+    } else {
+        LM_DBG("t_continue: transaction found\n");
+    }
+    //we have T, lets restore our state (esp. for AVPs)
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    if (is_timeout != 0) {
+        LM_ERR("Error timeout when sending AAR message via CDP\n");
+        update_stat(stat_aar_timeouts, 1);
+        goto error;
+    }
+    if (!aaa) {
+        LM_ERR("Error sending message via CDP\n");
+        goto error;
+    }
+
+    update_stat(aar_replies_received, 1);
+    update_stat(aar_replies_response_time, elapsed_msecs);
+
+    /* Process the response to AAR, retrieving result code and associated Rx session ID */
+    if (rx_process_aaa(aaa, &cdp_result) < 0) {
+        LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s);
+        goto error;
+    }
+
+    if (cdp_result >= 2000 && cdp_result < 3000) {
+        LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result);
+
+        LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);
+
+        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+        passed_rx_session_id->s = 0;
+        passed_rx_session_id->len = 0;
+        STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
+        LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);
+
+        dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+        result = CSCF_RETURN_TRUE;
+    } else {
+        LM_DBG("Received negative reply from PCRF for AAR Request\n");
+        //we don't free rx_authdata_p here - it is free-ed when the CDP session expires
+        goto error; // if its not a success then that means i want to reject this call!
+    }
+
+    //set success response code AVP
+    create_return_code(result);
+    goto done;
+
+out_of_memory:
+    error :
+            //set failure response code
+            create_return_code(result);
+
+done:
+    if (t) tmb.unref_cell(t);
+    //free memory
+    if (aaa)
+        cdpb.AAAFreeMessage(&aaa);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_transaction_global_data(data);
+}
+
+void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) {
     struct cell *t = 0;
     pcontact_t* pcontact;
     unsigned int cdp_result;
@@ -139,12 +234,12 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
     }
 
     if (cdp_result >= 2000 && cdp_result < 3000) {
-    	if (is_rereg) {
-    		LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
-    		result = CSCF_RETURN_TRUE;
-    		create_return_code(result);
-    		goto done;
-    	}
+        if (is_rereg) {
+            LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n");
+            result = CSCF_RETURN_TRUE;
+            create_return_code(result);
+            goto done;
+        }
         LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n",
                 cdp_result, local_data->contact.len, local_data->contact.s,
                 local_data->auth_session_id.len, local_data->auth_session_id.s);
@@ -166,7 +261,7 @@ void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
             ul.unlock_udomain(domain_t, &local_data->contact);
             goto error;
         }
-        memset(&ci, 0, sizeof(struct pcontact_info));
+        memset(&ci, 0, sizeof (struct pcontact_info));
         ci.reg_state = PCONTACT_REG_PENDING_AAR;
         ci.num_service_routes = 0;
         ci.num_public_ids = 0;
@@ -231,17 +326,17 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
     sdp_stream_cell_t* req_sdp_stream, *rpl_sdp_stream;
 
     if (!req || !rpl) {
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (parse_sdp(req) < 0) {
         LM_ERR("Unable to parse req SDP\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     if (parse_sdp(rpl) < 0) {
         LM_ERR("Unable to parse res SDP\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }
 
     sdp_session_num = 0;
@@ -312,13 +407,18 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
  * @returns AAA message or NULL on error
  */
 
-AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
-        AAASession* auth, str* callid, str* ftag, str* ttag, char* direction,
-        rx_authsessiondata_t **rx_authdata) {
+int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
+        AAASession* auth, char* direction, saved_transaction_t* saved_t_data) {
+
     AAAMessage* aar = 0;
-    AAAMessage* aaa = 0;
+
+
+    //AAAMessage* aaa = 0;
+
+
     AAA_AVP* avp = 0;
     char x[4];
+    int ret = 0;
 
     str ip;
     uint16_t ip_version;
@@ -444,11 +544,21 @@ AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res,
 
     LM_DBG("sending AAR to PCRF\n");
     if (rx_forced_peer.len)
-        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
+        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
+            (void*) async_aar_callback, (void*) saved_t_data);
     else
-        aaa = cdpb.AAASendRecvMessage(aar);
+        ret = cdpb.AAASendMessage(aar, (void*) async_aar_callback,
+            (void*) saved_t_data);
 
-    return aaa;
+    return ret;
+
+    //    LM_DBG("sending AAR to PCRF\n");
+    //    if (rx_forced_peer.len)
+    //        aaa = cdpb.AAASendRecvMessageToPeer(aar, &rx_forced_peer);
+    //    else
+    //        aaa = cdpb.AAASendRecvMessage(aar);
+    //
+    //    return aaa;
 
 error:
     LM_ERR("unexpected error\n");
@@ -459,7 +569,7 @@ error:
         cdpb.AAADropAuthSession(auth);
         auth = 0;
     }
-    return NULL;
+    return ret;
 }
 
 /**
@@ -470,8 +580,9 @@ error:
  * @param ip_version - AF_INET or AF_INET6
  * @returns int >0 if sent AAR successfully, otherwise 0
  */
+
 int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip,
-        uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data) {
+        uint16_t *ip_version, saved_transaction_local_t* saved_t_data) {
     AAAMessage* aar = 0;
     int ret = 0;
     AAA_AVP* avp = 0;
@@ -531,9 +642,9 @@ int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip,
     LM_DBG("sending AAR to PCRF\n");
     if (rx_forced_peer.len)
         ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
-            (void*) async_cdp_callback, (void*) saved_t_data);
+            (void*) async_aar_reg_callback, (void*) saved_t_data);
     else
-        ret = cdpb.AAASendMessage(aar, (void*) async_cdp_callback,
+        ret = cdpb.AAASendMessage(aar, (void*) async_aar_reg_callback,
             (void*) saved_t_data);
 
     return ret;
@@ -573,16 +684,27 @@ enum dialog_direction get_dialog_direction(char *direction) {
 void free_saved_transaction_global_data(saved_transaction_t* data) {
     if (!data)
         return;
-
-    lock_dealloc(data->lock);
-    lock_destroy(data->lock);
+    if (data->callid.s && data->callid.len) {
+        shm_free(data->callid.s);
+        data->callid.len = 0;
+    }
+    if (data->ftag.s && data->ftag.len) {
+        shm_free(data->ftag.s);
+        data->ftag.len = 0;
+    }
+    if (data->ttag.s && data->ttag.len) {
+        shm_free(data->ttag.s);
+        data->ttag.len = 0;
+    }
+    if (data->lock) {
+        lock_dealloc(data->lock);
+        lock_destroy(data->lock);
+    }
     shm_free(data);
 }
 
 void free_saved_transaction_data(saved_transaction_local_t* data) {
     if (!data)
         return;
-
-
     shm_free(data);
 }

+ 13 - 13
modules/ims_qos/rx_aar.h

@@ -57,16 +57,6 @@
 struct cdp_binds cdpb;
 cdp_avp_bind_t *cdp_avp;
 
-/*storage for data coming into AAR_register from config file
- * holds next action (async CDP) and domain
- */
-typedef struct aar_param {
-	int type;
-	udomain_t* domain;
-	cfg_action_t *paction;
-} aar_param_t;
-
-
 /*this is the parcel to pass for CDP async for AAR*/
 typedef struct saved_transaction {
 	gen_lock_t *lock;
@@ -78,6 +68,9 @@ typedef struct saved_transaction {
 	unsigned int ticks;
 	cfg_action_t *act;
 	udomain_t* domain;
+        str callid;
+        str ftag;
+        str ttag;
 } saved_transaction_t;
 
 typedef struct saved_transaction_local {
@@ -101,12 +94,19 @@ struct rx_authdata;
 void free_saved_transaction_data(saved_transaction_local_t* data);
 void free_saved_transaction_global_data(saved_transaction_t* data);
 
-AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
-int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
+//AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
+int rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, char *direction, saved_transaction_t* saved_t_data);
+
+//TODOD remove - no longer user AOR parm
+//int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
+int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, saved_transaction_local_t* saved_t_data);
+
 int rx_process_aaa(AAAMessage *aaa, unsigned int * rc);
 enum dialog_direction get_dialog_direction(char *direction);
 
-void async_cdp_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
+void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
+
+void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs);
 
 #endif
 

+ 2 - 0
modules/ims_qos/rx_authdata.c

@@ -79,6 +79,7 @@ int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** sess
 	memset(p_session_data, 0, len);
 
 	p_session_data->subscribed_to_signaling_path_status = 1;
+        p_session_data->must_terminate_dialog = 0; /*irrelevent for reg session data this will always be 0 */
 
 	char* p = (char*)(p_session_data + 1);
 	p_session_data->domain.s = p;
@@ -112,6 +113,7 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, rx_authsession
 	}
 	memset(call_session_data, 0, len);
 	call_session_data->subscribed_to_signaling_path_status = 0; //this is for a media session not regitration
+        call_session_data->must_terminate_dialog = 0; //this is used to determine if the dialog must be torn down when the CDP session terminates
 
 	char *p = (char*)(call_session_data + 1);
 

+ 1 - 0
modules/ims_qos/rx_authdata.h

@@ -69,6 +69,7 @@ typedef struct rx_authsessiondata {
     int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
     str domain;				//the domain the registration aor belongs to (for registration)
     str registration_aor; //the aor if this rx session is a subscription to signalling status
+    int must_terminate_dialog; //0 means when this session terminates it must not terminate the relevant dialog, 1 means it must terminate the dialog
 } rx_authsessiondata_t;
 
 int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);

+ 13 - 8
modules/ims_qos/rx_avp.c

@@ -56,6 +56,8 @@
 #include "rx_avp.h"
 #include "mod.h"
 
+#include "../../lib/ims/ims_getters.h"
+
 /**< Structure with pointers to cdp funcs, global variable defined in mod.c  */
 extern struct cdp_binds cdpb;
 extern cdp_avp_bind_t *cdp_avp;
@@ -86,7 +88,7 @@ inline int rx_add_avp(AAAMessage *m, char *d, int len, int avp_code,
         cdpb.AAAFreeAVP(&avp);
         return 0;
     }
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -122,7 +124,7 @@ static inline int rx_add_avp_list(AAA_AVP_LIST *list, char *d, int len, int avp_
         avp->prev = 0;
     }
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 }
 
 /**
@@ -272,7 +274,7 @@ inline int rx_add_destination_realm_avp(AAAMessage *msg, str data) {
  * Creates and adds an Acct-Application-Id AVP.
  * @param msg - the Diameter message to add to.
  * @param data - the value for the AVP payload
- * @return RX_RETURN_TRUE on success or 0 on error
+ * @return CSCF_RETURN_TRUE on success or 0 on error
  */
 inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data) {
     char x[4];
@@ -292,7 +294,7 @@ inline int rx_add_auth_application_id_avp(AAAMessage *msg, unsigned int data) {
  * @param msg - the Diameter message to add to.
  * @param r - the sip_message to extract the data from.
  * @param tag - originating (0) terminating (1)
- * @return RX_RETURN_TRUE on success or 0 on error
+ * @return CSCF_RETURN_TRUE on success or 0 on error
  * 
  */
 
@@ -503,8 +505,11 @@ static str permit_out = {"permit out ", 11};
 static str permit_in = {"permit in ", 10};
 static str from_s = {" from ", 6};
 static str to_s = {" to ", 4};
-static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
-static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
+//removed final %s - this is options which Rx 29.214 says will not be used for flow-description AVP
+static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u";
+//static char * permit_out_with_ports = "permit out %i from %.*s %u to %.*s %u %s";
+static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u";
+//static char * permit_in_with_ports = "permit in %i from %.*s %u to %.*s %u %s";
 
 AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
         str *ipA, str *portA,
@@ -549,13 +554,13 @@ AAA_AVP *rx_create_media_subcomponent_avp(int number, char* proto,
     }
 
     set_4bytes(x, number);
-
+    
     flow_number = cdpb.AAACreateAVP(AVP_IMS_Flow_Number,
             AAA_AVP_FLAG_MANDATORY | AAA_AVP_FLAG_VENDOR_SPECIFIC,
             IMS_vendor_id_3GPP, x, 4,
             AVP_DUPLICATE_DATA);
     cdpb.AAAAddAVPToList(&list, flow_number);
-
+    
     /*IMS Flow descriptions*/
     /*first flow is the receive flow*/
     flow_data.len = snprintf(flow_data.s, len, permit_out_with_ports, proto_int,

+ 7 - 5
modules/ims_qos/rx_str.c

@@ -58,6 +58,8 @@
 #include "rx_avp.h"
 #include "rx_str.h"
 
+#include "../../lib/ims/ims_getters.h"
+
 extern str IMS_Serv_AVP_val;
 
 int rx_send_str(str *rx_session_id) {
@@ -72,7 +74,7 @@ int rx_send_str(str *rx_session_id) {
 
     if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
         LM_ERR("Dialog has no Rx session associated\n");
-        return RX_RETURN_FALSE;
+        return CSCF_RETURN_FALSE;
     }else
     {
         LM_DBG("Rx session id exists\n");
@@ -82,8 +84,8 @@ int rx_send_str(str *rx_session_id) {
     LM_DBG("About to try get Auth session\n");
     auth = cdpb.AAAGetAuthSession(*rx_session_id);
     if (!auth) {
-        LM_ERR("Could not get Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
-        return RX_RETURN_FALSE;
+        LM_DBG("Could not get Auth Session for session id: [%.*s] - this is fine as this might have been started by already sending an STR\n", rx_session_id->len, rx_session_id->s);
+        return CSCF_RETURN_FALSE;
     }else{
         LM_DBG("Retrieved Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
     }
@@ -155,7 +157,7 @@ int rx_send_str(str *rx_session_id) {
 
     LM_DBG("Successfully sent Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
 
-    return RX_RETURN_TRUE;
+    return CSCF_RETURN_TRUE;
 
 error:
     LM_DBG("Error sending Rx STR for session: [%.*s]\n", rx_session_id->len, rx_session_id->s);
@@ -166,5 +168,5 @@ error:
         auth = 0;
     }
 
-    return RX_RETURN_FALSE;
+    return CSCF_RETURN_FALSE;
 }