LibSip_Steps.ttcn 144 KB
Newer Older
			case (mw_attribute_sendrecv) {return(valueof(m_attribute_sendrecv));}//MRO	
			case (mw_attribute_inactive) {return(valueof(m_attribute_inactive));}//MRO
			case (mw_attribute_recvonly) {return(valueof(m_attribute_sendonly));}//MRO
		}
		return(valueof(m_attribute_sendrecv));//the default return value in case of missing attribute offer  
	}

	/** 
	*  @desc check if message body include SDP bandwidth (2nd parameter)
	*		 either for the session or a media description
	*/
	function f_check_bandwidth(in SDP_Message loc_sdp, in template SDP_bandwidth loc_bandw) runs on SipComponent return boolean {
	
					if (ispresent(loc_sdp.bandwidth)) {
						for (var integer j:=0; j<sizeof(loc_sdp.bandwidth); j:=j+1){			
							if (match(loc_sdp.bandwidth[j],loc_bandw)) {return(true);};
							};
					};
					if (ispresent(loc_sdp.media_list)) {
						for (var integer j:=0; j<sizeof(loc_sdp.media_list); j:=j+1){
poglitsch's avatar
poglitsch committed
							if (ispresent(loc_sdp.media_list[j].bandwidth)) {
							 for(var integer i:=0; i< sizeof(loc_sdp.media_list[j].bandwidth); i:=i+1) {
								if (match(loc_sdp.media_list[j].bandwidth[i],loc_bandw)) {
									return(true);};
							 }
							}
						};
					};
    	
		return(false);
	}

	/** 
	*  @desc check if message body include SDP media (2nd parameter)
	*		 
	*/
	function f_check_media(in SDP_Message loc_sdp, in template SDP_media_desc loc_media) runs on SipComponent return boolean {
		
    	if (ispresent(loc_sdp.media_list)) {
    		for (var integer j:=0; j<sizeof(loc_sdp.media_list); j:=j+1){			
    			if (match(loc_sdp.media_list[j].media_field.transport,loc_media.media_field.transport) and
    				match(loc_sdp.media_list[j].media_field.fmts,loc_media.media_field.fmts)) 
    				{return(true);};
    			};
    	}
    	return(false);
poglitsch's avatar
poglitsch committed
	}
	
	/**
	 * @desc
	 *     check if message body include precondition mechanism (a=des and
	 *     a=curr) retrun true, else false
	 * @param loc_sdp SDP message
	 */
	function f_check_precondition(in SDP_Message loc_sdp) runs on SipComponent return boolean {
    	if (f_check_attribute(loc_sdp, mw_attribute_des) or
    		f_check_attribute(loc_sdp, mw_attribute_curr)) 
    		{return(true);}
    		
    	return(false);
	}	
			

	/** 
	*  @desc check if message body include SDP media direction return true, else false
	*		 
	*/
	function f_check_media_direction(in SDP_Message loc_sdp) runs on SipComponent return boolean {
		
    	if (f_check_attribute(loc_sdp, mw_attribute_sendonly) or
    		f_check_attribute(loc_sdp, mw_attribute_recvonly) or
    		f_check_attribute(loc_sdp, mw_attribute_sendrecv) or
    		f_check_attribute(loc_sdp, mw_attribute_inactive)) 
    		{return(true);}
    		
    	return(false);
	}		

	/** 
	*  @desc copy media/attribute lines from remote to local SDP variable
	*		 
	*/
	function f_check_SDP(integer loc_sdp, integer loc_codec) runs on SipComponent
	return boolean
	{
		var SDP_media_desc v_media := f_prepare_media(loc_sdp,loc_codec);
		log("log0"); 
		if (vc_sdp_remote.media_list[0].media_field.media != v_media.media_field.media)
			{ log("log1"); return false };
		if (vc_sdp_remote.media_list[0].media_field.transport != v_media.media_field.transport)
			{ log("log2"); return false };
		if (vc_sdp_remote.media_list[0].media_field.fmts != v_media.media_field.fmts)
			{ log("remote:",vc_sdp_remote.media_list[0].media_field.fmts,"expect:",v_media.media_field.fmts); return false };
			
		return true
	}
	
poglitsch's avatar
poglitsch committed
	/**
	 * @desc replace the first curr media attribute with the given value.
	 * @param p_sdp SDP message to modify
	 * @param p_curr new curr attribute
	 */
	function f_replace_curr_attribute(inout SDP_Message p_sdp, in SDP_attribute_curr p_curr) {
		if(ispresent(p_sdp.media_list)) {
			var integer mn := sizeof(p_sdp.media_list[0].attributes);
			for(var integer i := 0; i<=mn; i := i+1) {
				if(ischosen(p_sdp.media_list[0].attributes[i].curr)){
					p_sdp.media_list[0].attributes[i].curr := p_curr;
					i:=mn; 
				}	
			}
		}
	}
	
	/**
	 * @desc append new media attribute to the first media description.
	 * @param p_sdp SDP message to modify
	 * @param p_att SDP attribute to appand
	 */
	function f_append_media_attribute(inout SDP_Message p_sdp, in SDP_attribute p_att) {
		if(ispresent(p_sdp.media_list)) {
			var integer mn := sizeof(p_sdp.media_list[0].attributes);
			p_sdp.media_list[0].attributes[mn] := p_att;
		}
	}
	
	
	/** 
	*  @desc append new media to the existing media list in SDP
	*		 
	*/
	function f_append_media(inout SDP_Message loc_SDP, in template SDP_media_desc loc_media)
	{
		var integer mn := sizeof(loc_SDP.media_list);
		loc_SDP.media_list[mn] := valueof(loc_media);
	}
	/** 
	*  @desc repare media/attribute lines
	*		 
	*/
	function f_prepare_media(integer loc_sdp, integer loc_codec) runs on SipComponent
	return SDP_media_desc
	{
		var charstring v_codecs[32] := {
			"PCMU/8000", "GSM/8000", "G723/8000", "DVI4/8000",
			"DVI4/16000", "LPC/8000", "PCMA/8000", "G722/8000",
			"L16/44100/2", "L16/44100", "QCELP/8000", "CN/8000",
			"MPA/90000", "G728/8000", "DVI4/11025", "DVI4/22050",
			"G729/8000", "G726-40/8000", "G726-32/8000", "G726-24/8000",
			"G726-16/8000", "G726D/8000", "G726E/8000", "GSM-EFR/8000",
			"CelB/90000", "JPEG/90000", "Nv/90000", "H261/90000",
			"MPV/90000", "MP2T/90000", "H263/90000", "H263-1998/90000"
		}
		var SDP_media_desc v_media :=
			{
				media_field := {
					media := "audio",
					ports := { 
						port_number := 10000, 
						num_of_ports:=omit },
					transport := "RTP/AVP",
					fmts := { "0" }
				}, //m=audio 8500 RTP/AVP 0
				information := omit,
				connections := omit,
				bandwidth := omit,
				key := omit,						
				attributes := omit
			};
			
		if (32<loc_codec or loc_codec<1) {
			log("Unexpected SDP variant");
			setverdict(inconc); 
			return (v_media)}

		if (loc_sdp == 1) {}
		else if (loc_sdp == 2) {
			v_media.media_field.fmts := {PX_SIP_SDP_dyn}; //{ "98", "0" };
			v_media.attributes := {{
			rtpmap := { attr_value := PX_SIP_SDP_dyn & " " & v_codecs[loc_codec-1] } // PX_SIP_SDP_dyn := 98
			}}
		} else if (loc_sdp == 3) {
			v_media.media_field.fmts := { "8" }
		} else if (loc_sdp == 4) {
			v_media.media_field.fmts := { "99", "8" };
			v_media.attributes := {{
				rtpmap := { attr_value := "99 " & v_codecs[loc_codec-1] }
						}}
		} else if (loc_sdp == 5) {
			v_media.media_field.media := "image";
			v_media.media_field.transport := "udptl";
			v_media.media_field.fmts := { "t38" }
		} else if (loc_sdp == 6) {
			v_media.media_field.media := "image";
			v_media.media_field.transport := "tcptl";
			v_media.media_field.fmts := { "t38" }
		} else {
			log("Unexpected SDP variant"); setverdict(inconc) 
		};
			
		return (v_media);
	}

	/** 
	*  @desc repare media/attribute lines
	*		 
	*/
	function f_prepare_SDP(integer loc_sdp, integer loc_codec) runs on SipComponent
	{

		vc_sdp_local.media_list := {f_prepare_media(loc_sdp,loc_codec)};
	}
	
	/**
	* 
	* @desc function that copy media/attribute lines from remote to local SDP variable
	*/
	function f_prepare_SDP_answer() runs on SipComponent
	{
		var integer mn, cn := 0, i, j, k :=0;
		var charstring v_PT, v_rtpmap := "";
		var SDP_attribute_list v_mediaAttributes := {};
		//increase session version
		vc_sdp_local.origin.session_version := 	int2str(str2int(vc_sdp_remote.origin.session_version)+1);
		// if more than one codec, select the firs one
		mn:= sizeof(vc_sdp_remote.media_list);
		for (i :=0;  i < mn; i := i+1)
		{
			//for every single media
			if (ispresent(vc_sdp_remote.media_list[i].attributes))
				cn := sizeof(vc_sdp_remote.media_list[i].attributes);
			if (sizeof(vc_sdp_remote.media_list[i].media_field.fmts)>0) 
			{
				// select the first one
				v_PT := vc_sdp_remote.media_list[i].media_field.fmts[0];
				vc_sdp_local.media_list[i].media_field.fmts := {v_PT};
				for (j :=0; j<cn; j:=j+1)
				{
					if (ischosen(vc_sdp_remote.media_list[i].attributes[j].rtpmap))
						if (v_PT == regexp(vc_sdp_remote.media_list[i].attributes[j].rtpmap.attr_value,	"[ \t]#(0,)([\d]+)*", 0))
							v_rtpmap := vc_sdp_remote.media_list[i].attributes[j].
							rtpmap.attr_value;
							v_mediaAttributes[k] := {rtpmap := {attr_value := v_rtpmap}};
							k := k+1;
						} // else line is not copied
					}
					else 
					{
						// simple copy of attribute
						v_mediaAttributes[k] := vc_sdp_remote.media_list[i].attributes[j];
						k := k+1;
					}
				}
				vc_sdp_local.media_list[i].attributes := v_mediaAttributes;
				
                if (ispresent(vc_sdp_local.media_list[i].attributes))
                {
                    cn := sizeof(vc_sdp_local.media_list[i].attributes);
                    for (j :=0; j<cn; j:=j+1)
                    {
    					 // simplified handling of status attributes (copy/keep status from peer):
                         // a) copy/keep SDP_attribute_curr (invert tags if applicable)
                         if (ischosen(vc_sdp_local.media_list[i].attributes[j].curr))
                         {
                             // invert local/remote status tags
                             if (vc_sdp_local.media_list[i].attributes[j].curr.statusType == "local")
                                 {vc_sdp_local.media_list[i].attributes[j].curr.statusType := "remote"};
                             if (vc_sdp_local.media_list[i].attributes[j].curr.statusType == "remote")
                                 {vc_sdp_local.media_list[i].attributes[j].curr.statusType := "local"};
                             // invert send/recv direction tags
                             if (vc_sdp_local.media_list[i].attributes[j].curr.direction == "send")
                                 {vc_sdp_local.media_list[i].attributes[j].curr.direction := "recv"};
                             if (vc_sdp_local.media_list[i].attributes[j].curr.direction == "recv")
                                 {vc_sdp_local.media_list[i].attributes[j].curr.direction := "send"};
                         }				
                         // b) copy/keep SDP_attribute_des (keep strength, invert tags if applicable)	
                         else if (ischosen(vc_sdp_local.media_list[i].attributes[j].des))
                         {
                             // invert local/remote status tags
                             if (vc_sdp_local.media_list[i].attributes[j].des.statusType == "local")
                                 {vc_sdp_local.media_list[i].attributes[j].des.statusType := "remote"};
                             if (vc_sdp_local.media_list[i].attributes[j].des.statusType == "remote")
                                 {vc_sdp_local.media_list[i].attributes[j].des.statusType := "local"};
                             // invert send/recv direction tags
                             if (vc_sdp_local.media_list[i].attributes[j].des.direction == "send")
                                 {vc_sdp_local.media_list[i].attributes[j].des.direction := "recv"};
                             if (vc_sdp_local.media_list[i].attributes[j].des.direction == "recv")
                                 {vc_sdp_local.media_list[i].attributes[j].des.direction := "send"};
                         }				
                         // c) simplification: assume no SDP_attribute_conf	
                         else if (ischosen(vc_sdp_local.media_list[i].attributes[j].conf))
                         {
                             // todo: handle SDP_attribute_conf
                         }
                    }
                };
				
			}
		}
		// add handling of prenegotiation, change ports if required etc.
		//if prenegotiation...
	}

	/** 
	*  @desc reject SDP offer by setting media ports to 0
	*		 
	*/
	function f_reject_SDP_offer() runs on SipComponent
	{
		var integer mn, i;
		f_copy_SDP(); // TO BE DONE with more details!
		//increase session version
		vc_sdp_local.origin.session_version := int2str(str2int(vc_sdp_local.origin.session_version)+1);
		// if more than one codec, select the firs one
		mn:= sizeof(vc_sdp_local.media_list);
		for (i :=0;  i < mn; i := i+1)
		{
			vc_sdp_local.media_list[i].media_field.ports := {0, omit};
			vc_sdp_local.media_list[i].attributes := omit; //{};
		};
	}

rennoch's avatar
rennoch committed
	/**
rennoch's avatar
rennoch committed
	 * @desc 	copies SDP message elements from remote to local component variable: 
	 * 				- bandwidth
	 * 				- session version (will be incremented)
	 * 				- media list
	 * 			modify the direction attribute of an SDP media list entry within an SDP message (vc_sdp_local)
	 * @param 	p_medianum 		list position number of the media (if value 0 identifies first media list element)
	 * @param 	p_direction		the new direction attribute to be included in the media entry
rennoch's avatar
rennoch committed
	 * @verdict 
	 */
	function f_SIP_modMediaDirection(integer p_medianum, template SDP_attribute p_direction) runs on SipComponent
	{
rennoch's avatar
rennoch committed
		var boolean v_set_direction; // flag indicates if direction attribute has been modified
		var integer v_mn := 0; 		 // length of media list (number of entries)
		var integer v_cn := 0; 		 // number of attributes of a media entry
		var integer i, j, k := 0;
		var SDP_attribute_list v_mediaAttributes := {}; // collect the media attributes (to be assigned at end of function)
		
		f_copy_SDP(); // copy SDP session bandwidth and media list from remote to local component variable
		
		// increment session version
		vc_sdp_local.origin.session_version := int2str(str2int(vc_sdp_local.origin.session_version)+1);
rennoch's avatar
rennoch committed
		
		// if more than one codec, select the first one
		v_mn:= sizeof(vc_sdp_local.media_list);

		if (p_medianum == 0) //specific media requested
rennoch's avatar
rennoch committed
    		{
    			p_medianum := 1; // start checking from first media
    		};
		if (p_medianum > 0) //specific media requested
rennoch's avatar
rennoch committed
    		{
    			if (not(p_medianum > v_mn)) 
    				{v_mn := p_medianum}
    		};
    		
		// handling of media list elements
		for (i :=0;  i < v_mn; i := i+1)
		{
rennoch's avatar
rennoch committed
			v_cn := 0; // initialize the number of attributes of the media list entry
rennoch's avatar
rennoch committed
			if (ispresent(vc_sdp_local.media_list)) //media_list is optional
			{						
//				log("vc_sdp_local.media_list[i] ",vc_sdp_local.media_list[i]);
				if (ispresent(vc_sdp_local.media_list[i].attributes))
				{
					v_cn := sizeof(vc_sdp_local.media_list[i].attributes);
				};
				
				v_set_direction := false;
				//if (sizeof(vc_sdp_local.media_list[i].media_field.fmts)>1) 
				// select the first one
rennoch's avatar
rennoch committed
				for (j :=0; j<v_cn; j:=j+1)
				{ 
					if (ischosen(vc_sdp_local.media_list[i].attributes[j].recvonly)
							or ischosen(vc_sdp_local.media_list[i].attributes[j].sendonly)
							or ischosen(vc_sdp_local.media_list[i].attributes[j].inactive)
							or ischosen(vc_sdp_local.media_list[i].attributes[j].sendrecv))
						{
							v_mediaAttributes[k] := valueof(p_direction); 
							v_set_direction := true;
						}
				 		else // non-direction attributes will be copied
						{
							v_mediaAttributes[k] := vc_sdp_local.media_list[i].attributes[j];
							k := k+1;
						}
				}
				
				if (not v_set_direction) 
					{ v_mediaAttributes[k] := valueof(p_direction)};
				vc_sdp_local.media_list[i].attributes := v_mediaAttributes;
    				
		}	 
		// add handling of prenegotiation, change ports if required etc.
		//if prenegotiation...
	}
	
     /** 
     *  @desc modify session and media attributes direction
     *		 
     */
     function f_SIP_modSessionDirection(template SDP_attribute p_direction) runs on SipComponent
     {
juvancic's avatar
juvancic committed
      var boolean v_set_direction := false;
      var integer v_mn:= 0, i:=0;
      
	  if (ispresent(vc_sdp_local.attributes))
		{ v_mn:= sizeof(vc_sdp_local.attributes);			
       
          for (i :=0;  i < v_mn; i := i+1)
          {//for every single attribute (that is not omit)    
                 if (ischosen(vc_sdp_local.attributes[i].recvonly)
                   or ischosen(vc_sdp_local.attributes[i].sendonly)
                   or ischosen(vc_sdp_local.attributes[i].inactive)
                   or ischosen(vc_sdp_local.attributes[i].sendrecv))
                 {
juvancic's avatar
juvancic committed
                    vc_sdp_local.attributes[i] := valueof(p_direction);
                  	v_set_direction := true;
                 }
           }
           if (not v_set_direction) // if not sent before
juvancic's avatar
juvancic committed
           { 
               vc_sdp_local.attributes[v_mn] := valueof(p_direction);
           };
		} 
		else 
		{vc_sdp_local.attributes[0] := valueof(p_direction)};    
     * 
     * @desc check (from remote) and set (local) the session/media attribute lines on directions
     * @param p_direction_in incoming SDP attribute that need to be checked
     * @param p_direction_out SDP attribute that should be included in the SDP answer (to be returned to peer)
     * @return 
     * @verdict 
     */	
	function f_SIP_checksetSDPreqDirection(template SDP_attribute p_direction_in, template SDP_attribute p_direction_out) runs on SipComponent
	{	var template SDP_attribute v_direction_out := p_direction_out;
		// check incoming SDP attribute
		log(vc_request.messageBody.sdpMessageBody);log(p_direction_in);
		if (not (ispresent(vc_request.messageBody) and (f_check_attribute(vc_request.messageBody.sdpMessageBody,p_direction_in)
			))) 
			{log("than branch of if");
			    if (
schmitting's avatar
schmitting committed
			    match(valueof(p_direction_in),valueof(mw_attribute_sendrecv)) and
			    not(f_check_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_sendrecv) or
                 f_check_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_sendonly) or
                 f_check_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_recvonly) or
                 f_check_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_inactive)
			    )
			    ){
				log("no direction attributes with expectation: ", p_direction_in)			
				}
			    else {setverdict(fail);};}
			  else {setverdict(pass);log("attribute found in message body");};
  		if (match(omit,p_direction_out))//not isvalue(v_direction_out))//MRO
			{v_direction_out := f_get_attribute_answer(vc_request.messageBody.sdpMessageBody, p_direction_in);}
		f_SIP_modMediaDirection(1, v_direction_out); // handling of attribute in media description
		f_SIP_modSessionDirection(v_direction_out); // handling of attribute in session		
	}

    /*
     * 
     * @desc check (from remote) and set (local) the session/media attribute lines on directions
     * @param p_direction_in incoming SDP attribute that need to be checked
     * @param p_direction_out SDP attribute that should be included in the SDP answer (to be returned to peer)
     * @return 
     * @verdict 
     */	
    function f_SIP_checkResponsesetSDPreqDirection(template SDP_attribute p_direction_in, template SDP_attribute p_direction_out) runs on SipComponent
    {	var template SDP_attribute v_direction_out := p_direction_out;
        // check incoming SDP attribute
        log(vc_response.messageBody.sdpMessageBody);log(p_direction_in);
        if (not (ispresent(vc_response.messageBody) and (f_check_attribute(vc_response.messageBody.sdpMessageBody,p_direction_in)
            ))) 
            {log("than branch of if");
                if (
schmitting's avatar
schmitting committed
                match(valueof(p_direction_in),valueof(mw_attribute_sendrecv)) and
                not(f_check_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_sendrecv) or
                 f_check_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_sendonly) or
                 f_check_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_recvonly) or
                 f_check_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_inactive)
                )
                ){
                log("no direction attributes with expectation: ", p_direction_in)			
                }
                else {setverdict(fail);};}
              else {setverdict(pass);log("attribute found in message body");};
        if (match(omit,p_direction_out))//not isvalue(v_direction_out))//MRO
            {v_direction_out := f_get_attribute_answer(vc_response.messageBody.sdpMessageBody, p_direction_in);}
        f_SIP_modMediaDirection(1, v_direction_out); // handling of attribute in media description
        f_SIP_modSessionDirection(v_direction_out); // handling of attribute in session		
    }
	
    /*
     * 
     * @desc check (from remote) and set (local) the session attribute lines on directions
     * @param p_direction_in incoming SDP attribute that need to be checked
     * @param p_direction_out SDP attribute that should be included in the SDP answer (to be returned to peer)
     * @return 
     * @verdict 
     */	
    function f_SIP_checksetSDPreqDirectionSession(template SDP_attribute p_direction_in, template SDP_attribute p_direction_out) runs on SipComponent
    {	var template SDP_attribute v_direction_out := p_direction_out;
        // check incoming SDP attribute
        if (not (ispresent(vc_request.messageBody) and (f_check_session_attribute(vc_request.messageBody.sdpMessageBody,p_direction_in)
            ))) 
            {if (
schmitting's avatar
schmitting committed
                match(valueof(mw_attribute_sendrecv),valueof(p_direction_in)) and
                not(f_check_session_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_sendrecv) or
                f_check_session_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_sendonly) or
                f_check_session_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_recvonly) or
                f_check_session_attribute(vc_request.messageBody.sdpMessageBody,mw_attribute_inactive)
                )
                ){
                log("no direction attributes with expectation: ", p_direction_in)			
                }
                else {setverdict(fail);};};
        if (match(omit,p_direction_out))//not isvalue(v_direction_out))//MRO
            {v_direction_out := f_get_attribute_answer(vc_request.messageBody.sdpMessageBody, p_direction_in);}
        f_SIP_modSessionDirection(v_direction_out); // handling of attribute in session		
    }
    /*
     * 
     * @desc check (from remote) and set (local) the session attribute lines on directions
     * @param p_direction_in incoming SDP attribute that need to be checked
     * @param p_direction_out SDP attribute that should be included in the SDP answer (to be returned to peer)
     * @return 
     * @verdict 
     */	
    function f_SIP_checkResponsesetSDPreqDirectionSession(template SDP_attribute p_direction_in, template SDP_attribute p_direction_out) runs on SipComponent
    {	var template SDP_attribute v_direction_out := p_direction_out;
        // check incoming SDP attribute
        if (not (ispresent(vc_response.messageBody) and (f_check_session_attribute(vc_response.messageBody.sdpMessageBody,p_direction_in)
            ))) 
            {if (
schmitting's avatar
schmitting committed
                match(valueof(mw_attribute_sendrecv),valueof(p_direction_in)) and
                not(f_check_session_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_sendrecv) or
                f_check_session_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_sendonly) or
                f_check_session_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_recvonly) or
                f_check_session_attribute(vc_response.messageBody.sdpMessageBody,mw_attribute_inactive)
                )
                ){
                log("no direction attributes with expectation: ", p_direction_in)			
                }
                else {setverdict(fail);};};
        if (match(omit,p_direction_out))//not isvalue(v_direction_out))//MRO
            {v_direction_out := f_get_attribute_answer(vc_response.messageBody.sdpMessageBody, p_direction_in);}
        f_SIP_modSessionDirection(v_direction_out); // handling of attribute in session		
    }


	/*
		* 
		* @desc check (from remote) and set (local)the session/media attribute lines on directions
		* @param p_direction_in attribute to be check
		* @param p_direction_out attrubyte to be 
		* @return 
		* @verdict 
		*/	
    function f_SIP_checkSDPrespDirection(template SDP_attribute p_direction_in) runs on SipComponent
    {		
    	// check incoming SDP attribute
    	if (not (ispresent(vc_response.messageBody) and f_check_attribute(vc_response.messageBody.sdpMessageBody,p_direction_in))) 
    		{setverdict(fail);};
    }

	/** 
	*  @desc check media/attribute lines from remote
	*		 
	*/
	function f_SIP_checkMediaDirection(integer p_medianum, template SDP_attribute p_direction) runs on SipComponent
	return boolean
	{
		var integer v_mn, v_cn := 0, i, j;
		var boolean v_result := false;
		//increase session version
		vc_sdp_remote.origin.session_version := int2str(str2int(vc_sdp_remote.origin.session_version)+1);
		// if more than one codec, select the firs one
		v_mn:= sizeof(vc_sdp_remote.media_list);
		if (p_medianum == 0) //specific media requested
		{
			p_medianum := 1; // start checking from first media
		};
		if (p_medianum > 0) //specific media requested
		{
			if (p_medianum > v_mn) {return false}
			else {v_mn := p_medianum}
		};
		for (i :=p_medianum-1;  i < v_mn; i := i+1)
		{
			//for every single media
			if (ispresent(vc_sdp_remote.media_list[i].attributes))
			{
				v_cn := sizeof(vc_sdp_remote.media_list[i].attributes);
				log (v_cn);
			};
			if (sizeof(vc_sdp_remote.media_list[i].attributes)>0) 
			{
				// select the first one
				log(vc_sdp_remote.media_list[i].attributes);
				for (j :=0; j<sizeof(vc_sdp_remote.media_list[i].attributes); j:=j+1)
				{
					log(vc_sdp_remote.media_list[i].attributes[j]);
					if (ischosen(vc_sdp_remote.media_list[i].attributes[j].recvonly)
							or ischosen(vc_sdp_remote.media_list[i].attributes[j].sendonly)
							or ischosen(vc_sdp_remote.media_list[i].attributes[j].inactive)
							or ischosen(vc_sdp_remote.media_list[i].attributes[j].sendrecv))
					{
						if (match(vc_sdp_remote.media_list[i].attributes[j],p_direction))
						{ v_result :=  true; }
						else { return  false; }
					}

					//v_result :=  true; // TODO This is a shortcut since direction attributes are not decoded
				}
			}
		}
		return v_result
	}

	/** 
	*  @desc copy media/attribute lines from remote to local SDP variable
	*		 
	*/
	function f_copy_SDP() runs on SipComponent
		if (ispresent(vc_sdp_remote.connection))
				{vc_sdp_local.connection := vc_sdp_remote.connection}
			else {vc_sdp_local.connection := omit};
			
        vc_sdp_local.origin := vc_sdp_remote.origin;
        vc_sdp_local.session_name := vc_sdp_remote.session_name;
			
        if (ispresent(vc_sdp_remote.bandwidth))
                {vc_sdp_local.bandwidth := vc_sdp_remote.bandwidth}
            else {vc_sdp_local.bandwidth := {}};
		if (ispresent(vc_sdp_remote.media_list))
		{
rennoch's avatar
rennoch committed
                //			// cleaning of media before assignment	
                //			if (ispresent(vc_sdp_local.media_list))
                //			{
                //				for (var integer i:=0; i<sizeof(vc_sdp_local.media_list); i:=i+1)
                //				{			
                //					vc_sdp_local.media_list[i] := omit ; 						  
                //				}			
                //			};		
			vc_sdp_local.media_list := vc_sdp_remote.media_list;
		}
	}
}//end group SDPOperations

group AwaitingMessage {
   
    /**
     * 
     * @desc Function for time delay 
     */
    function f_awaitingDelayTimer(float p_delay) runs on SipComponent
    {
      tc_tDelay.start(p_delay);
      alt
      {
        [] tc_tDelay.timeout
          {
            setverdict (pass);
          }
      }
    } //end f_awaitingDelayTimer
	
	/**
	 * 
	 * @desc Function waiting for any MSG -request/response 
	 */
	function f_awaitingAnyPassOnTimeout() runs on SipComponent
	{
	  tc_wait.start(PX_SIP_TWAIT);
	  alt
	  {
		[] SIPP.receive	//TAU error if expect (*)
		  {
			tc_wait.stop;
			vc_boo_response:=true;
			vc_boo_request:=true;
			//setverdict(pass)
		  }
		[] tc_wait.timeout
		  {
			vc_boo_response:=false;
			vc_boo_request:=false;
			//setverdict (pass)
		  }
	  }
	} //end f_awaitingResponsePassOnTimeout

	/**
	 * 
	 * @desc Function waiting for no MSG -request/response 
	 */
	function f_awaitingNonePassOnTimeout() runs on SipComponent
	{
	  tc_wait.start(PX_SIP_TWAIT);
	  alt
	  {
		[] tc_wait.timeout
		  {
			setverdict (pass);
		  }
	  }
	} //end f_awaitingResponsePassOnTimeout
		
	/**
	 * 
	 * @desc function awaits REGISTER
	 * @param p_register expected REGISTER request
	 */	
 	function f_awaitingREGISTER(in template REGISTER_Request p_register) runs on SipComponent
	{
 		tc_wait.start(PX_SIP_TWAIT);
		alt
		{
		  [] SIPP.receive(p_register)-> value v_request sender vc_sent_label
			{
			  f_setHeadersOnReceiptOfREGISTER(v_request);
			}
          [] tc_wait.timeout
			  f_componentStop();               
		}		
	}
	
	/**
	 * 
	 * @desc function awaits SUBSCRIBE
	 * @param p_register expected SUBSCRIBE request
	 */	
	function f_awaitingSUBSCRIBE(in template SUBSCRIBE_Request p_subscribe) runs on SipComponent
		tc_wait.start(PX_SIP_TWAIT);
		  [] SIPP.receive(p_subscribe)-> value v_request sender vc_sent_label
			  f_setHeadersOnReceiptOfSUBSCRIBE(v_request);
			}
          [] SIPP.receive(mw_SUBSCRIBE_Request_Base)-> value v_request sender vc_sent_label
            {
              tc_wait.stop;
              setverdict(fail);
              f_setHeadersOnReceiptOfSUBSCRIBE(v_request);
              //f_send200OK();
            }
	 * 
	 * @desc function awaits REGISTER and sends a 200 OK response
	 * @param p_reply flag used to avoid the 200OK response sending
	 */	
 	function f_awaitingREGISTER_sendReply(in template REGISTER_Request p_register, in boolean p_reply) runs on SipComponent
	{
		var Request	v_request;
      
		tc_wait.start(PX_SIP_TWAIT);
		alt
		{
		  [] SIPP.receive(p_register)-> value v_request sender vc_sent_label
			{
			  vc_request := v_request;
			  f_setHeadersOnReceiptOfREGISTER(v_request);
			  //Answer to the Request
			  if (p_reply) {f_send200OK();};
			}
		  [] tc_wait.timeout
			  f_componentStop(); 
	 * 
	 * @desc Function waiting for a 200 OK response
	 * @param p_cSeq_s current cSeq expectation
	 */
	function f_awaitingOkResponse(inout CSeq p_cSeq_s) runs on SipComponent
	{ 

  	tc_resp.start(PX_SIP_TRESP);
  	alt
  	{
		[] SIPP.receive	(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) -> value vc_response
			f_setHeadersOnReceiptOfResponse(vc_cSeq, vc_response);
			setverdict(pass)
  	}
	} //end awaitingOkResponse

	/**
	 * 
	 * @desc Function waiting for a response
	 * @param p_Response expected response message
	 */
	function f_awaitingResponse(in template Response p_Response) runs on SipComponent
	{
	  tc_resp.start(PX_SIP_TRESP);
	  alt
	  {
		[] SIPP.receive	(p_Response) -> value vc_response
		  {
			f_setHeadersOnReceiptOfResponse(vc_cSeq, vc_response);
			//setverdict(pass)
	/**
		* 
		* @desc Function waiting for a response and send ACK on FailureResponses 4xx,5xx,6xx
		* @param p_Response expected response message
		*/
	function f_awaitingResponseSendACK(in template Response p_Response) runs on SipComponent
	{
		tc_resp.start(PX_SIP_TRESP);
poglitsch's avatar
poglitsch committed
    	alt {
			[] SIPP.receive	(p_Response) -> value vc_response {
poglitsch's avatar
poglitsch committed
    			f_setHeadersOnReceiptOfResponse(vc_cSeq, vc_response);
				LibSip_Steps.f_setHeadersACK();
poglitsch's avatar
poglitsch committed
				f_SendACK(m_ACK_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via));
    			setverdict(pass);
poglitsch's avatar
poglitsch committed
    	}
	} //end f_awaitingResponse
	
	/**
		 * 
		 * @desc Function waiting for a response
		 * @param p_Response expected response message
		 */
		function f_awaitingResponsePassOnTimeout(in template Response p_Response) runs on SipComponent
		{
		  tc_resp.start(PX_SIP_TRESP);
		  alt
		  {
			[] SIPP.receive	(p_Response) -> value vc_response
			  {
				f_setHeadersOnReceiptOfResponse(vc_cSeq, vc_response);
				vc_boo_response:=true;
				//setverdict(pass)
			  }
			[] tc_resp.timeout
			  {
			  	vc_boo_response:=false;
			  	//setverdict (pass)
			  }
		  }
		} //end f_awaitingResponsePassOnTimeout
	
	/** 
	*  @desc await INFO request
	*		 reply with 200 OK
	*/
	function f_awaitingINFO_sendReply(in template INFO_Request p_info) runs on SipComponent
		var INFO_Request	v_request;
		tc_wait.start(PX_SIP_TWAIT);
		  [] SIPP.receive(p_info)-> value v_request sender vc_sent_label
			  tc_wait.stop;
			  f_setHeadersOnReceiptOfRequest(v_request);
			  //Answer to the INFO
			  f_send200OK();
			}
		}
	} // end of f_awaitingINFO_sendReply
	
	 * 
	 * @desc function awaiting for an incoming INVITE
	 * @param p_request expected message
	 */
	function f_awaitingINVITE(template INVITE_Request p_request) runs on SipComponent
	{
	  var INVITE_Request v_INVITE_Request;
      
	  tc_wait.start(PX_SIP_TWAIT);
	  alt
	  {
		[]SIPP.receive	(p_request) -> value v_INVITE_Request sender vc_sent_label
		  { 
			tc_wait.stop;
			vc_ignore_invite := true;
			vc_first_recv:= true; // communication has started
			f_setHeadersOnReceiptOfINVITE(v_INVITE_Request);
			SIPP.send(m_Response_Base(c_statusLine100, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)) to vc_sent_label;
		  }
        [vc_interface_isc]SIPP.receive	(mw_INVITE_Request_Base) -> value v_INVITE_Request sender vc_sent_label
          { 
            tc_wait.stop;
            setverdict(fail);
            f_setHeadersOnReceiptOfINVITE(v_INVITE_Request);
            SIPP.send(m_Response_Base(c_statusLine100, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)) to vc_sent_label;
			//clear session - send 486 and await ACK
            f_sendResponse(m_Response_Base(c_statusLine486,vc_callId,vc_cSeq,vc_caller_From,vc_caller_To,vc_via));
            f_awaitingACK(mw_ACK_Request_Base(?));
            //await 486 which go towards and send ACK        
            f_awaitingResponse(mw_Response_Base(c_statusLine486,?,?));
            f_SendACK(m_ACK_Request_Base(vc_requestUri,vc_callId,vc_cSeq,vc_from,vc_to,vc_via));
            syncPort.send(m_syncClientStop);
            stop
          }
	} //end f_awaitingINVITE

	/**
		* 
		* @desc function awaiting for an incoming INVITE
		* @param p_request expected message
		*/
	function f_awaitingINVITE_No100Response(template INVITE_Request p_request) runs on SipComponent
	{
	  var INVITE_Request v_INVITE_Request;
      
      tc_wait.start(PX_SIP_TWAIT);
      alt
      {
    	[]SIPP.receive	(p_request) -> value v_INVITE_Request sender vc_sent_label
    	  { 
    		tc_wait.stop;
    		vc_ignore_invite := true;
    		vc_first_recv:= true; // communication has started
    		f_setHeadersOnReceiptOfINVITE(v_INVITE_Request);
    	    //SIPP.send(m_Response_Base(c_statusLine100, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)) to vc_sent_label;
    	  }
      }
	} //end f_awaitingInviteRequest

	/**
	 * 
	 * @desc function awaiting for an incoming INVITE
	 * @param p_request expected message
	 */
	function f_awaitingINVITE_PassOnTimeout(template INVITE_Request p_request) runs on SipComponent
	{
	  var INVITE_Request v_INVITE_Request;
      
	  tc_wait.start(PX_SIP_TWAIT);
	  alt
	  {
		[]SIPP.receive	(p_request) -> value v_INVITE_Request sender vc_sent_label
		  { 
			tc_wait.stop;
			vc_ignore_invite := true;
			vc_first_recv:= true; // communication has started
			vc_boo_request := true;
			f_setHeadersOnReceiptOfINVITE(v_INVITE_Request);
			SIPP.send(m_Response_Base(c_statusLine100, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)) to vc_sent_label;
		  }