浏览代码

modules/ims_qos: store AAR flow descriptions in CDP session
When flow_descriptions are installed save the active and new
This allows Rx to fallback to previous flow descriptions if there is an upstream failure

Richard Good 11 年之前
父节点
当前提交
e5c9f00606

+ 1 - 2
modules/ims_qos/cdpeventprocessor.c

@@ -265,8 +265,7 @@ void cdp_cb_event_process() {
 
                 //free callback data
                 if (p_session_data) {
-                    shm_free(p_session_data);
-                    p_session_data = 0;
+		    free_callsessiondata(p_session_data);
                 }
                 break;
             default:

+ 175 - 17
modules/ims_qos/mod.c

@@ -332,25 +332,169 @@ AAAMessage* callback_cdp_request(AAAMessage *request, void *param) {
     return 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");
+const str match_cseq_method = {"INVITE", 6};
 
+void callback_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
+    
+    struct sip_msg* msg = params->rpl;
+    struct cseq_body *parsed_cseq;
     str *rx_session_id;
     rx_session_id = (str*) * params->param;
+    AAASession *auth = 0;
+    rx_authsessiondata_t* p_session_data = 0;
+    flow_description_t *current_fd = 0;
+    flow_description_t *new_fd = 0;
+    int current_has_video = 0;
+    int new_has_video = 0;
+    int must_unlock_aaa = 1;
+    
+    //getting session data
+    
+    LM_DBG("Dialog callback of type %d received\n", type);
+    
+    if(type == DLGCB_TERMINATED || type == DLGCB_DESTROY || type == DLGCB_EXPIRED){
+	   LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
 
-    if (!rx_session_id) {
-        LM_ERR("Invalid Rx session id");
-        return;
-    }
+	LM_DBG("Received notification of termination of dialog with Rx session ID: [%.*s]\n",
+		rx_session_id->len, rx_session_id->s);
 
-    LM_DBG("Received notification of termination of dialog with Rx session ID: [%.*s]\n",
-            rx_session_id->len, rx_session_id->s);
+	LM_DBG("Sending STR\n");
+	rx_send_str(rx_session_id);
+    } else if (type == DLGCB_CONFIRMED){
+	
+	LM_DBG("Callback for confirmed dialog - copy new flow description into current flow description\n");
+	if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
+	    LM_ERR("Dialog has no Rx session associated\n");
+	    goto error;
+	}
 
-    LM_DBG("Retrieving Rx auth data for this session id");
+	//getting auth session
+	auth = cdpb.AAAGetAuthSession(*rx_session_id);
+	if (!auth) {
+	    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);
+	    goto error;
+	}
 
-    LM_DBG("Sending STR\n");
-    rx_send_str(rx_session_id);
+	//getting session data
+	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+	if (!p_session_data) {
+	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
+
+	//check if there is a new flow description - if there is then free the current flow description and replace it with the new flow description
+	if(p_session_data->first_new_flow_description) {
+	    //free the current
+	    LM_DBG("Free-ing the current fd\n");
+	    free_flow_description(p_session_data, 1);
+	    //point the current to the new
+	    LM_DBG("Point the first current fd to the first new fd\n");
+	    p_session_data->first_current_flow_description = p_session_data->first_new_flow_description;
+	    //point the new to 0
+	    LM_DBG("Point the first new fd to 0\n");
+	    p_session_data->first_new_flow_description = 0;
+	} else {
+	    LM_ERR("There is no new flow description - this shouldn't happen\n");
+	}
+	
+	show_callsessiondata(p_session_data);
+	if (auth) cdpb.AAASessionsUnlock(auth->hash);
+    
+    } else if (type == DLGCB_RESPONSE_WITHIN){
+	
+	LM_DBG("Dialog has received a response to a request within dialog\n");
+	if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
+	    LM_ERR("Dialog has no Rx session associated\n");
+	    goto error;
+	}
 
+	//getting auth session
+	auth = cdpb.AAAGetAuthSession(*rx_session_id);
+	if (!auth) {
+	    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);
+	    goto error;
+	}
+
+	//getting session data
+	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+
+	if (!p_session_data) {
+	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
+	
+	show_callsessiondata(p_session_data);
+
+	if (msg->first_line.type == SIP_REPLY) {
+	    LM_DBG("This is a SIP REPLY\n");
+	    if (msg->cseq && (parsed_cseq = get_cseq(msg)) && memcmp(parsed_cseq->method.s, match_cseq_method.s, match_cseq_method.len)==0) {
+		LM_DBG("This response has a cseq method [%.*s]\n", match_cseq_method.len, match_cseq_method.s);
+		
+		if (msg->first_line.u.reply.statuscode == 200) {
+		    LM_DBG("Response is 200 - this is success\n");
+		    //check if there is a new flow description - if there is then free the current flow description and replace it with the new flow description
+		    if(p_session_data->first_new_flow_description) {
+			//free the current
+			free_flow_description(p_session_data, 1);
+			//point the current to the new
+			p_session_data->first_current_flow_description = p_session_data->first_new_flow_description;
+			//point the new to 0
+			p_session_data->first_new_flow_description = 0;
+		    } else {
+			LM_DBG("There is no new flow description - duplicate dialog callback - we ignore.\n");
+		    }
+		} else if (msg->first_line.u.reply.statuscode > 299) {
+		    LM_DBG("Response is more than 299 so this is an error code\n");
+		    
+		    new_fd = p_session_data->first_new_flow_description;
+		    //check if there is video in the new flow description
+		    while(new_fd) {
+			if (strncmp(new_fd->media.s, "video", 5) == 0) {
+			    LM_DBG("The new flow has a video fd in it\n");
+			    new_has_video = 1;
+			    
+			}
+			new_fd = new_fd->next;
+		    }
+		    //check if there is video in the current flow description
+		    current_fd = p_session_data->first_current_flow_description;
+		    while(current_fd) {
+			if (strncmp(current_fd->media.s, "video", 5) == 0) {
+			    LM_DBG("The current flow has a video fd in it\n");
+			    current_has_video = 1;
+			    
+			}
+			current_fd = current_fd->next;
+		    }
+		    if(new_has_video && !current_has_video) {
+			LM_DBG("New flow description has video in it, and current does not - this means we added video and it failed further upstream - "
+				"so we must remove the video\n");
+			//We need to send AAR asynchronously with current fd
+			rx_send_aar_update_no_video(auth);
+			must_unlock_aaa = 0;
+			
+		    } 
+		    //free the new flow description
+		    free_flow_description(p_session_data, 0);
+		}
+	    }
+	}
+	
+	show_callsessiondata(p_session_data);
+		
+	if(must_unlock_aaa)
+	{
+	    LM_DBG("Unlocking AAA session");
+	    cdpb.AAASessionsUnlock(auth->hash);
+	}
+    } else {
+	LM_DBG("Callback type not supported - just returning");
+    }
+    
+    return;
+    
+    error:
+	if (auth) cdpb.AAASessionsUnlock(auth->hash);
     return;
 }
 
@@ -390,6 +534,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     
     str route_name;
     str identifier, ip;
+    int ip_version = 0;
     int must_free_asserted_identity = 0;
     sdp_session_cell_t* sdp_session;
 
@@ -508,6 +653,8 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     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;
+    
+    saved_t_data->aar_update = 0;//by default we say this is not an aar update - if it is we set it below
 
     //store branch
     int branch;
@@ -564,6 +711,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
 		    goto error;
 	    }
 	    ip = sdp_session->ip_addr;
+	    ip_version = sdp_session->pf;
 	    free_sdp((sdp_info_t**) (void*) &t->uas.request->body);
 	    
 	} else {
@@ -585,11 +733,12 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
 		    goto error;
 	    }
 	    ip = sdp_session->ip_addr;
+	    ip_version = sdp_session->pf;
 	    free_sdp((sdp_info_t**) (void*) &msg->body);
 	    
 	}
 
-        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &identifier, &ip, &rx_authdata_p);
+        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &identifier, &ip, ip_version, &rx_authdata_p);
         if (!ret) {
             LM_DBG("Unable to create new media session data parcel\n");
             goto error;
@@ -607,8 +756,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
             LM_ERR("Rx: unable to create new Rx Media Session\n");
             if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
             if (rx_authdata_p) {
-                shm_free(rx_authdata_p);
-                rx_authdata_p = 0;
+		free_callsessiondata(rx_authdata_p);
             }
             goto error;
         }
@@ -625,18 +773,28 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     } else {
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
 	auth_session = cdpb.AAAGetAuthSession(*rx_session_id);
+	
+	    if (!auth_session) {
+	    LM_ERR("Could not get Auth Session for session id: [%.*s] on AAR update\n", rx_session_id->len, rx_session_id->s);
+	    result = CSCF_RETURN_FALSE; //here we return FALSE this just drops the message in the config file
+	    goto error;
+	}
+	
 	if(auth_session->u.auth.state != AUTH_ST_OPEN)
 	{
 	    LM_DBG("This session is not state open, packet will be dropped");
+	    if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
 	    result = CSCF_RETURN_FALSE; //here we return FALSE this just drops the message in the config file
 	    goto error;
 	}
+	saved_t_data->aar_update = 1;//this is an update aar - we set this so on async_aar we know this is an update and act accordingly
     }
 
     LM_DBG("Suspending SIP TM transaction\n");
     if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
         LM_ERR("failed to suspend the TM processing\n");
-        goto error;
+	if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
+	goto error;
     }
 
     LM_DBG("Sending Rx AAR");
@@ -645,7 +803,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     if (!ret) {
         LM_ERR("Failed to send AAR\n");
         tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
-        goto error;
+	goto error;
 
 
     } else {
@@ -666,7 +824,7 @@ error:
 	    must_free_asserted_identity = 1;
     }
 
-     return result;
+    return result;
 }
 
 /* Wrapper to send AAR from config file - only used for registration */

+ 1 - 1
modules/ims_qos/mod.h

@@ -57,7 +57,7 @@ struct pcontact;
 AAAMessage* callback_cdp_request(AAAMessage *request, void *param);
 void callback_for_cdp_session(int event,void *session);
 
-void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params);
+void callback_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params * params);
 
 void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param);
 

+ 217 - 19
modules/ims_qos/rx_aar.c

@@ -135,14 +135,17 @@ void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
         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);
+	
+	if(!data->aar_update) {
+	    LM_DBG("This is an AAA response to an initial AAR");
+	    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 | DLGCB_RESPONSE_WITHIN | DLGCB_CONFIRMED, callback_dialog, (void*) (passed_rx_session_id), free_dialog_data);
+	} 
         result = CSCF_RETURN_TRUE;
     } else {
         LM_DBG("Received negative reply from PCRF for AAR Request\n");
@@ -316,10 +319,33 @@ int rx_process_aaa(AAAMessage *aaa, unsigned int * rc) {
     return ret;
 }
 
+/** Helper function for adding media component AVPs - uses previously stored flow descriptions not SDP from messages*/
+int add_media_components_using_current_flow_description(AAAMessage* aar, rx_authsessiondata_t *p_session_data) {
+    
+    flow_description_t *flow_description;
+    
+    flow_description = p_session_data->first_current_flow_description;
+    if(!flow_description) {
+	return -1;
+    }
+    while (flow_description) {
+        rx_add_media_component_description_avp(aar, flow_description->stream_num,
+	    &flow_description->media, &flow_description->req_sdp_ip_addr,
+	    &flow_description->req_sdp_port, &flow_description->rpl_sdp_ip_addr,
+	    &flow_description->rpl_sdp_port, &flow_description->rpl_sdp_transport,
+	    &flow_description->req_sdp_raw_stream,
+	    &flow_description->rpl_sdp_raw_stream, flow_description->direction);
+	
+	flow_description = flow_description->next;
+    }
+    return 0;
+}
+
+
+
 /** Helper function for adding media component AVPs for each SDP stream*/
 int add_media_components(AAAMessage* aar, struct sip_msg *req,
-        struct sip_msg *rpl, enum dialog_direction direction,
-        uint16_t *ip_version) {
+        struct sip_msg *rpl, enum dialog_direction direction, AAASession* auth) {
     int sdp_session_num;
     int sdp_stream_num;
     sdp_session_cell_t* req_sdp_session, *rpl_sdp_session;
@@ -359,13 +385,6 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
             break;
         }
 
-	//we only populate ip if its not already populated
-        if (direction == DLG_MOBILE_ORIGINATING) {
-            *ip_version = req_sdp_session->pf;
-        } else if (direction == DLG_MOBILE_TERMINATING) {
-            *ip_version = rpl_sdp_session->pf;
-        }
-
         sdp_stream_num = 0;
         for (;;) {
             req_sdp_stream = get_sdp_stream(req, sdp_session_num,
@@ -383,7 +402,17 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
 		int intportA = atoi(req_sdp_stream->port.s);
 		int intportB = atoi(rpl_sdp_stream->port.s);
 		if(intportA != 0 && intportB != 0){
-                	rx_add_media_component_description_avp(aar, sdp_stream_num + 1,
+		    
+			//add this to auth session data
+			
+			add_flow_description((rx_authsessiondata_t*) auth->u.auth.generic_data, sdp_stream_num + 1,
+                        	&req_sdp_stream->media, &req_sdp_session->ip_addr,
+	                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
+        	                &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
+                	        &req_sdp_stream->raw_stream,
+                        	&rpl_sdp_stream->raw_stream, direction, 0 /*This is a new mcd, we are not setting it as active*/);
+		    
+			rx_add_media_component_description_avp(aar, sdp_stream_num + 1,
                         	&req_sdp_stream->media, &req_sdp_session->ip_addr,
 	                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
         	                &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
@@ -402,6 +431,171 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
     return 0;
 }
 
+/**
+ * Sends the Authorization Authentication Request - specifically this is an asynchronous AAR sent if another update adding video has failed so we need to remove video
+ */
+
+int rx_send_aar_update_no_video(AAASession* auth) {
+
+    AAAMessage* aar = 0;
+    int must_free_asserted_identity = 0;
+    
+    str identifier;
+    int identifier_type;
+
+
+    AAA_AVP* avp = 0;
+    char x[4];
+    int ret = 0;
+
+    str ip;
+    uint16_t ip_version;
+
+    //we get ip and identifier for the auth session data 
+    rx_authsessiondata_t* p_session_data = 0;
+    p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+    identifier = p_session_data->identifier;
+    ip = p_session_data->ip;
+    ip_version = p_session_data->ip_version;
+    
+    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);
+
+    LM_DBG("Sending AAR update to remove a video bearer\n");
+    show_callsessiondata(p_session_data);
+
+    if (!aar)
+        goto error;
+
+    /*Adding AVPs*/
+
+    LM_DBG("Adding auth app id AVP...\n");
+    /* Add Auth-Application-Id AVP */
+    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
+        goto error;
+    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
+            IMS_Rx))
+        goto error;
+
+    LM_DBG("Adding dest realm if not there already...\n");
+    /* Add Destination-Realm AVP, if not already there */
+    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
+            0, AAA_FORWARD_SEARCH);
+    if (!avp) {
+        str realm = rx_dest_realm;
+        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
+            goto error;
+    }
+
+    LM_DBG("Adding AF App identifier...\n");
+    /* Add AF-Application-Identifier AVP */
+    str af_id = {0, 0};
+    af_id = IMS_Serv_AVP_val;
+    if (!rx_add_avp(aar, af_id.s, af_id.len, AVP_IMS_AF_Application_Identifier,
+            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+            __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding service info status...\n");
+    /* Add Service-Info-Status AVP, if prelimiary
+     * by default(when absent): final status is considered*/
+    
+    set_4bytes(x,
+	    AVP_EPC_Service_Info_Status_Preliminary_Service_Information);
+    if (!rx_add_avp(aar, x, 4, AVP_IMS_Service_Info_Status,
+	    AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+	    __FUNCTION__))
+	goto error;
+
+    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
+    if (rx_auth_expiry) {
+        set_4bytes(x, rx_auth_expiry);
+        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
+                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
+            goto error;
+    }
+
+    LM_DBG("Adding subscription id...\n");
+
+    if (strncasecmp(identifier.s,"tel:",4)==0) {
+	identifier_type = AVP_Subscription_Id_Type_E164; //
+    }else{
+	identifier_type = AVP_Subscription_Id_Type_SIP_URI; //default is END_USER_SIP_URI
+    }
+    
+    
+    rx_add_subscription_id_avp(aar, identifier, identifier_type);
+    if (must_free_asserted_identity) {
+            pkg_free(identifier.s);
+    }
+
+
+    LM_DBG("Adding reservation priority...\n");
+    /* Add Reservation Priority AVP*/
+    set_4bytes(x, 0);
+    if (!rx_add_avp(aar, x, 4, AVP_ETSI_Reservation_Priority,
+            AAA_AVP_FLAG_VENDOR_SPECIFIC, IMS_vendor_id_ETSI,
+            AVP_DUPLICATE_DATA, __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding media component...\n");
+    //Note we add this AVP first as it gets the IP address which we need to create the auth session
+    //Could and maybe should have a separate method that retrieves the IP from SDP - TODO
+
+    /*---------- 2. Create and add Media-Component-Description AVP ----------*/
+
+    /*
+     *  See 3GPP TS29214
+     *
+     *  <Media-Component-Description> = {Media-Component-Number}
+     * 								 	[Media-Sub-Component]
+     * 								 	[AF-Application-Identifier]
+     * 								 	[Media-Type]
+     * 								 	[Max-Requested-Bandwidth-UL]
+     * 									[Max-Requested-Bandwidth-DL]
+     * 									[Flow-Status]
+     * 									[Reservation-Priority] (Not used yet)
+     * 								 	[RS-Bandwidth]
+     * 									[RR-Bandwidth]
+     * 									*[Codec-Data]
+     */
+
+    add_media_components_using_current_flow_description(aar, p_session_data);
+
+    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
+    /* Add Framed IP address AVP*/
+    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
+        LM_ERR("Unable to add framed IP AVP\n");
+        goto error;
+    }
+    LM_DBG("Unlocking AAA session...\n");
+
+    if (auth)
+        cdpb.AAASessionsUnlock(auth->hash);
+
+    LM_DBG("sending AAR to PCRF\n");
+    if (rx_forced_peer.len)
+        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
+            NULL, NULL);
+    else
+        ret = cdpb.AAASendMessage(aar, NULL,
+            NULL);
+
+    return ret;
+
+error:
+    LM_ERR("unexpected error\n");
+    if (aar)
+        cdpb.AAAFreeMessage(&aar);
+    if (auth) {
+        cdpb.AAASessionsUnlock(auth->hash);
+        cdpb.AAADropAuthSession(auth);
+        auth = 0;
+    }
+    return ret;
+}
+
+
+
 /**
  * Sends the Authorization Authentication Request.
  * @param req - SIP request
@@ -433,6 +627,7 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
     p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
     identifier = p_session_data->identifier;
     ip = p_session_data->ip;
+    ip_version = p_session_data->ip_version;
     
     /* find direction for AAR (orig/term) */
     //need this to add the media component details
@@ -543,7 +738,7 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
      * 									*[Codec-Data]
      */
 
-    add_media_components(aar, req, res, dlg_direction, &ip_version);
+    add_media_components(aar, req, res, dlg_direction, auth);
 
     LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
     /* Add Framed IP address AVP*/
@@ -551,6 +746,9 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
         LM_ERR("Unable to add framed IP AVP\n");
         goto error;
     }
+    
+    show_callsessiondata(p_session_data);
+    
     LM_DBG("Unlocking AAA session...\n");
 
     if (auth)

+ 5 - 0
modules/ims_qos/rx_aar.h

@@ -71,6 +71,7 @@ typedef struct saved_transaction {
         str callid;
         str ftag;
         str ttag;
+	unsigned int aar_update;
 } saved_transaction_t;
 
 typedef struct saved_transaction_local {
@@ -97,6 +98,10 @@ 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(struct sip_msg *req, struct sip_msg *res, AAASession* auth, char *direction, saved_transaction_t* saved_t_data);
 
+//send AAR to remove video after failed AAR update that added video
+int rx_send_aar_update_no_video(AAASession* auth);
+
+
 //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);

+ 228 - 2
modules/ims_qos/rx_authdata.c

@@ -103,7 +103,7 @@ int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** sess
 	return 1;
 }
 
-int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str* ip, rx_authsessiondata_t** session_data) {
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str* ip, int ip_version, rx_authsessiondata_t** session_data) {
 
 	int len = callid->len + ftag->len + ttag->len + identifier->len + ip->len + sizeof(rx_authsessiondata_t);
 	rx_authsessiondata_t* call_session_data = shm_malloc(len);
@@ -114,7 +114,11 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifie
 	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
-
+	
+	call_session_data->first_current_flow_description=0;
+	call_session_data->first_new_flow_description=0;
+	call_session_data->ip_version = ip_version;
+	
 	char *p = (char*)(call_session_data + 1);
 
 	if (callid && callid->len>0 && callid->s) {
@@ -162,7 +166,229 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifie
 	return 1;
 }
 
+/* Param current tells us if this a current fd or a new fd to add*/
+int add_flow_description(rx_authsessiondata_t* session_data, int stream_num, str *media, str *req_sdp_ip_addr, str *req_sdp_port,
+			str *rpl_sdp_ip_addr, str *rpl_sdp_port, str *rpl_sdp_transport, str *req_sdp_raw_stream, str *rpl_sdp_raw_stream, int direction, int current) {
+    
+    flow_description_t *fd = 0;
+    flow_description_t *tmp, *tmp1 = 0;
+    
+    int len = media->len + req_sdp_ip_addr->len + req_sdp_port->len + rpl_sdp_ip_addr->len + rpl_sdp_port->len + rpl_sdp_transport->len + req_sdp_raw_stream->len + rpl_sdp_raw_stream->len + sizeof(flow_description_t);
+    fd = shm_malloc(len);
+    if (!fd){
+	    LM_ERR("no more shm mem trying to create new flow description of size %d\n", len);
+	    return -1;
+    }
+    memset(fd, 0, len);
+    
+    fd->direction = direction;
+    fd->stream_num = stream_num;
+    
+    char *p = (char*)(fd + 1);
 
+    if (media && media->len>0 && media->s) {
+	    LM_DBG("Copying media [%.*s] into flow description\n", media->len, media->s);
+	    fd->media.s = p;
+	    memcpy(fd->media.s, media->s, media->len);
+	    fd->media.len = media->len;
+	    p+=media->len;
+    }
+    if (req_sdp_ip_addr && req_sdp_ip_addr->len>0 && req_sdp_ip_addr->s) {
+	    LM_DBG("Copying req_sdp_ip_addr [%.*s] into flow description\n", req_sdp_ip_addr->len, req_sdp_ip_addr->s);
+	    fd->req_sdp_ip_addr.s = p;
+	    memcpy(fd->req_sdp_ip_addr.s, req_sdp_ip_addr->s, req_sdp_ip_addr->len);
+	    fd->req_sdp_ip_addr.len = req_sdp_ip_addr->len;
+	    p+=req_sdp_ip_addr->len;
+    }
+    if (req_sdp_port && req_sdp_port->len>0 && req_sdp_port->s) {
+	    LM_DBG("Copying req_sdp_port [%.*s] into flow description\n", req_sdp_port->len, req_sdp_port->s);
+	    fd->req_sdp_port.s = p;
+	    memcpy(fd->req_sdp_port.s, req_sdp_port->s, req_sdp_port->len);
+	    fd->req_sdp_port.len = req_sdp_port->len;
+	    p+=req_sdp_port->len;
+    }
+    if (rpl_sdp_ip_addr && rpl_sdp_ip_addr->len>0 && rpl_sdp_ip_addr->s) {
+	    LM_DBG("Copying rpl_sdp_ip_addr [%.*s] into flow description\n", rpl_sdp_ip_addr->len, rpl_sdp_ip_addr->s);
+	    fd->rpl_sdp_ip_addr.s = p;
+	    memcpy(fd->rpl_sdp_ip_addr.s, rpl_sdp_ip_addr->s, rpl_sdp_ip_addr->len);
+	    fd->rpl_sdp_ip_addr.len = rpl_sdp_ip_addr->len;
+	    p+=rpl_sdp_ip_addr->len;
+    }
+    if (rpl_sdp_port && rpl_sdp_port->len>0 && rpl_sdp_port->s) {
+	    LM_DBG("Copying rpl_sdp_port [%.*s] into flow description\n", rpl_sdp_port->len, rpl_sdp_port->s);
+	    fd->rpl_sdp_port.s = p;
+	    memcpy(fd->rpl_sdp_port.s, rpl_sdp_port->s, rpl_sdp_port->len);
+	    fd->rpl_sdp_port.len = rpl_sdp_port->len;
+	    p+=rpl_sdp_port->len;
+    }
+    if (rpl_sdp_transport && rpl_sdp_transport->len>0 && rpl_sdp_transport->s) {
+	    LM_DBG("Copying rpl_sdp_transport [%.*s] into flow description\n", rpl_sdp_transport->len, rpl_sdp_transport->s);
+	    fd->rpl_sdp_transport.s = p;
+	    memcpy(fd->rpl_sdp_transport.s, rpl_sdp_transport->s, rpl_sdp_transport->len);
+	    fd->rpl_sdp_transport.len = rpl_sdp_transport->len;
+	    p+=rpl_sdp_transport->len;
+    }
+    if (req_sdp_raw_stream && req_sdp_raw_stream->len>0 && req_sdp_raw_stream->s) {
+	    LM_DBG("Copying req_sdp_raw_stream [%.*s] into flow description\n", req_sdp_raw_stream->len, req_sdp_raw_stream->s);
+	    fd->req_sdp_raw_stream.s = p;
+	    memcpy(fd->req_sdp_raw_stream.s, req_sdp_raw_stream->s, req_sdp_raw_stream->len);
+	    fd->req_sdp_raw_stream.len = req_sdp_raw_stream->len;
+	    p+=req_sdp_raw_stream->len;
+    }
+    if (rpl_sdp_raw_stream && rpl_sdp_raw_stream->len>0 && rpl_sdp_raw_stream->s) {
+	    LM_DBG("Copying rpl_sdp_raw_stream [%.*s] into flow description\n", rpl_sdp_raw_stream->len, rpl_sdp_raw_stream->s);
+	    fd->rpl_sdp_raw_stream.s = p;
+	    memcpy(fd->rpl_sdp_raw_stream.s, rpl_sdp_raw_stream->s, rpl_sdp_raw_stream->len);
+	    fd->rpl_sdp_raw_stream.len = rpl_sdp_raw_stream->len;
+	    p+=rpl_sdp_raw_stream->len;
+    }
+	
+    if (p != ((char*)(fd) + len)) {
+	    LM_ERR("buffer under/overflow\n");
+	    shm_free(fd);
+	    return -1;
+    }
 
+    fd->next=0;
 
+    if(current){
+	LM_DBG("Adding current flow description\n");
+	    if(session_data->first_current_flow_description == 0) {
+		LM_DBG("This is the first\n");
+		session_data->first_current_flow_description = fd;
+	} else{
+	    LM_DBG("This is NOT the first - adding to the list\n");
+	    tmp = session_data->first_current_flow_description;
+	     while (tmp) {
+		tmp1 = tmp->next;
+		if(!tmp1) {
+		    break;
+		}
+		tmp = tmp1;
+	    }
+	    tmp->next = fd;
+	}
+    } else {
+	LM_DBG("Adding new flow description\n");
+	    if(session_data->first_new_flow_description == 0) {
+		LM_DBG("This is the first\n");
+		session_data->first_new_flow_description = fd;
+	} else{
+	    LM_DBG("This is NOT the first - adding to the list\n");
+	    tmp = session_data->first_new_flow_description;
+	    //scrolls to last valid entry
+	    while (tmp) {
+		tmp1 = tmp->next;
+		if(!tmp1) {
+		    break;
+		}
+		tmp = tmp1;
+	    }
+	    tmp->next = fd;
+	}
+    }
+    
+    return 1;
+}
+
+/* Param current tells us if this a current fd or a new fd to add*/
+void free_flow_description(rx_authsessiondata_t* session_data, int current) {
+    
+    flow_description_t *flow_description;
+    flow_description_t *flow_description_tmp;
+    if(!session_data){
+	return;
+    }
+    
+    if(current) {
+	LM_DBG("Destroy current flow description\n");
+	flow_description = session_data->first_current_flow_description;
+	if(!flow_description) {
+	    return;
+	}
+    } else {
+	LM_DBG("Destroy new flow description\n");
+	flow_description = session_data->first_new_flow_description;
+	if(!flow_description) {
+	    return;
+	}
+    }
+    
+    while (flow_description) {
+        flow_description_tmp = flow_description->next;
+        shm_free(flow_description);
+	flow_description = 0;
+	flow_description = flow_description_tmp;
+    }
+}
+
+void free_callsessiondata(rx_authsessiondata_t* session_data) {
+
+    if(!session_data){
+	return;
+    }
+    
+    LM_DBG("Destroy current flow description\n");
+    free_flow_description(session_data, 1);
+    
+    LM_DBG("Destroy new flow description\n");
+    free_flow_description(session_data, 0);
+    
+    LM_DBG("Destroy session data\n");
+    shm_free(session_data);
+    session_data = 0;
+}
+
+void show_callsessiondata(rx_authsessiondata_t* session_data) {
+    
+    flow_description_t *flow_description;
+    
+    if(!session_data){
+	return;
+    }
+    
+    LM_DBG("Session data:\n");
+    LM_DBG("=====================\n");
+    LM_DBG("Call id [%.*s]\n", session_data->callid.len, session_data->callid.s);
+    LM_DBG("Domain [%.*s]\n", session_data->domain.len, session_data->domain.s);
+    LM_DBG("Ftag [%.*s]\n", session_data->ftag.len, session_data->ftag.s);
+    LM_DBG("Ttag [%.*s]\n", session_data->ttag.len, session_data->ttag.s);
+    LM_DBG("Identifier [%.*s]\n", session_data->identifier.len, session_data->identifier.s);
+    LM_DBG("Registration AOR [%.*s]\n", session_data->registration_aor.len, session_data->registration_aor.s);
+    LM_DBG("IP [%.*s]\n", session_data->ip.len, session_data->ip.s);
+    LM_DBG("IP version [%d]\n", session_data->ip_version);
+    LM_DBG("Must terminate dialog [%d]\n", session_data->must_terminate_dialog);
+    LM_DBG("Subscribed to signalling path status [%d]\n", session_data->subscribed_to_signaling_path_status);
+    
+    flow_description = session_data->first_current_flow_description;
+    while(flow_description) {
+	LM_DBG("Current Flow description [%d]\n", flow_description->stream_num);
+	LM_DBG("\tMedia [%.*s]\n", flow_description->media.len, flow_description->media.s);
+	LM_DBG("\tReq_sdp_ip_addr [%.*s]\n", flow_description->req_sdp_ip_addr.len, flow_description->req_sdp_ip_addr.s);
+	LM_DBG("\tReq_sdp_port [%.*s]\n", flow_description->req_sdp_port.len, flow_description->req_sdp_port.s);
+	LM_DBG("\tReq_sdp_raw_stream [%.*s]\n", flow_description->req_sdp_raw_stream.len, flow_description->req_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_ip_addr [%.*s]\n", flow_description->rpl_sdp_ip_addr.len, flow_description->rpl_sdp_ip_addr.s);
+	LM_DBG("\tRpl_sdp_port [%.*s]\n", flow_description->rpl_sdp_port.len, flow_description->rpl_sdp_port.s);
+	LM_DBG("\tRpl_sdp_raw_stream [%.*s]\n", flow_description->rpl_sdp_raw_stream.len, flow_description->rpl_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_transport [%.*s]\n", flow_description->rpl_sdp_transport.len, flow_description->rpl_sdp_transport.s);
+	LM_DBG("\tDirection [%d]\n", flow_description->direction);
+	flow_description = flow_description->next;
+    }
+    flow_description = session_data->first_new_flow_description;
+    while(flow_description) {
+	LM_DBG("New Flow description [%d]\n", flow_description->stream_num);
+	LM_DBG("\tMedia [%.*s]\n", flow_description->media.len, flow_description->media.s);
+	LM_DBG("\tReq_sdp_ip_addr [%.*s]\n", flow_description->req_sdp_ip_addr.len, flow_description->req_sdp_ip_addr.s);
+	LM_DBG("\tReq_sdp_port [%.*s]\n", flow_description->req_sdp_port.len, flow_description->req_sdp_port.s);
+	LM_DBG("\tReq_sdp_raw_stream [%.*s]\n", flow_description->req_sdp_raw_stream.len, flow_description->req_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_ip_addr [%.*s]\n", flow_description->rpl_sdp_ip_addr.len, flow_description->rpl_sdp_ip_addr.s);
+	LM_DBG("\tRpl_sdp_port [%.*s]\n", flow_description->rpl_sdp_port.len, flow_description->rpl_sdp_port.s);
+	LM_DBG("\tRpl_sdp_raw_stream [%.*s]\n", flow_description->rpl_sdp_raw_stream.len, flow_description->rpl_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_transport [%.*s]\n", flow_description->rpl_sdp_transport.len, flow_description->rpl_sdp_transport.s);
+	LM_DBG("\tDirection [%d]\n", flow_description->direction);
+	flow_description = flow_description->next;
+    }
+    
+    LM_DBG("=====================\n");
+}
 

+ 25 - 1
modules/ims_qos/rx_authdata.h

@@ -61,21 +61,45 @@ enum dialog_direction {
     DLG_MOBILE_UNKNOWN = 4
 };
 
+typedef struct flow_description {
+    int stream_num;
+    str media;
+    str req_sdp_ip_addr;
+    str req_sdp_port;
+    str rpl_sdp_ip_addr;
+    str rpl_sdp_port;
+    str rpl_sdp_transport;
+    str req_sdp_raw_stream;
+    str rpl_sdp_raw_stream;
+    int direction;
+    struct flow_description *next;
+}flow_description_t;
+
 typedef struct rx_authsessiondata {
     str callid;
     str ftag;
     str ttag;
     str identifier;
     str ip;
+    int ip_version;
     //for registration session
     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
+    flow_description_t *first_current_flow_description;
+    flow_description_t *first_new_flow_description;
 } rx_authsessiondata_t;
 
 int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);
-int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str *ip, rx_authsessiondata_t** session_data);
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str *ip, int ip_version, rx_authsessiondata_t** session_data);
+void free_callsessiondata(rx_authsessiondata_t* session_data);
+
+int add_flow_description(rx_authsessiondata_t* session_data, int stream_num, str *media, str *req_sdp_ip_addr, str *req_sdp_port,
+			str *rpl_sdp_ip_addr, str *rpl_sdp_port, str *rpl_sdp_transport, str *req_sdp_raw_stream, str *rpl_sdp_raw_stream, int direction, int current);
+void free_flow_description(rx_authsessiondata_t* session_data, int current);
+
+void show_callsessiondata(rx_authsessiondata_t* session_data);
 
 #endif