/** * @author STF 346, STF366, STF368, STF369, STF450, STF471 * @version $Id$ * @desc This module provides the functions, altsteps and external functions used * for SIP-IMS tests. * This module is part of LibSipV3. */ module LibSip_Steps { // LibCommon import from LibCommon_Sync all; import from LibCommon_VerdictControl all; // LibSip import from LibSip_SIPTypesAndValues all; import from LibSip_SDPTypes all; import from LibSip_Templates all; import from LibSip_Interface all; import from LibSip_PIXITS all; import from LibSip_XMLTypes all; import from LibSip_Common all; group externalfunctions { /** * @desc External function to return random charstring */ external function fx_rndStr( ) return charstring; /** * @desc External function to return the equivalent string in lower case */ external function fx_putInLowercase( charstring p_string ) return charstring; /** * @desc External function to get IP address. */ external function fx_getIpAddr( charstring p_host_name ) return charstring; /** * @desc External function to generate a digest response. * @reference RFC 2617 HTTP Authentication: Basic and Digest Access Authentication, and RFC 1321 The MD5 Message-Digest Algorithm * @see RFC 2617, chapter 5 Sample implementation, for example usage, as the signature of calculateDigestResponse is according to the example given in the RFC. */ external function fx_calculateDigestResponse( charstring p_nonce, charstring p_cnonce, charstring p_user, charstring p_realm, charstring p_passwd, charstring p_alg, charstring p_nonceCount, charstring p_method, charstring p_qop, charstring p_URI, charstring p_HEntity ) return charstring; } group ParameterOperations { /** * @desc function to generate a 32 bits random number as a charstring for tag field (used as e.g.: tag in from-header field, or branch parameter in via header) * @return random value with at least 32 bits of randomness */ function f_getRndTag( ) return charstring { var charstring v_tag_value; // tag_value is initialized with a random value with at least 32 bits of randomness // 4294967296 is a 32 bits integer v_tag_value := fx_rndStr() & fx_rndStr(); return (v_tag_value); } /** * @desc Function to prepare credentials for request that has an empty entity body such as a REGISTER message. * @param p_userprofile to get important parameters * @param p_algorithm Algorthm to be used. Default: omit * @return Credentials field */ function f_calculatecCredentials_empty( in SipUserProfile p_userprofile, in boolean p_algorithm := false ) return Credentials { var Credentials v_result; // RFC 2617 3.2.2 username: // The name of user in the specified realm. var charstring v_username := p_userprofile.privUsername; var charstring v_realm := p_userprofile.registrarDomain; var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain; var CommaParam_List v_digestResponse := {}; // Construct credentials for an Authorization field of a request. v_digestResponse := f_addParameter(v_digestResponse, { id := "username", paramValue := { quotedString := v_username } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "realm", paramValue := { quotedString := v_realm } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "uri", paramValue := { quotedString := v_uri } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "nonce", paramValue := { quotedString := "" } }); // already enclosed to " characters v_digestResponse := f_addParameter(v_digestResponse, { id := "response", paramValue := { quotedString := "" } }); // already enclosed to " characters if (p_algorithm) { v_digestResponse := f_addParameter(v_digestResponse, { id := "algorithm", paramValue := { tokenOrHost := PX_AUTH_ALGORITHM } }); // already enclosed to " characters } v_result := {digestResponse := v_digestResponse}; return v_result; } /** * @desc Function to calculate credentials for request that has an empty entity body such as a REGISTER message. * @param p_userprofile to get important parameters * @param p_method (can be "REGISTER", "INVITE",....) * @param p_challenge parameter from 4xx response * @return Credentials field * @verdict */ function f_calculatecCredentials( in SipUserProfile p_userprofile, in charstring p_method, in CommaParam_List p_challenge ) return Credentials { var Credentials v_result; var charstring v_nonce := ""; var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265); // RFC 2617 3.2.2 username: // The name of user in the specified realm. var charstring v_username := p_userprofile.privUsername; var charstring v_realm; // RFC 2617 3.2.2.2 passwd: // A known shared secret, the password of user of the specified // username. var charstring v_passwd := p_userprofile.passwd; var charstring v_algorithm; // a new pseudo-random cnonce value is used every time // that assumes it is only used once const charstring cl_nonceCount := "00000001"; var charstring v_qop := p_userprofile.qop; var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain; // MD5 hash of empty entity body. const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e"; var charstring v_response; var charstring v_opaque; var CommaParam_List v_digestResponse := {}; // extract nonce, realm, algorithm, and opaque from challenge v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce"); v_realm := f_extractParamValueFromChallenge(p_challenge, "realm"); v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm"); v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque"); // calculate a digest response for the Authorize header v_response := fx_calculateDigestResponse(v_nonce, v_cnonce, v_username, v_realm, v_passwd, v_algorithm, cl_nonceCount, p_method, v_qop, v_uri, cl_hEntity); // Construct credentials for an Authorization field of a request. v_digestResponse := f_addParameter(v_digestResponse, { id := "username", paramValue := { quotedString := v_username } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "realm", paramValue := { quotedString := v_realm } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "nonce", paramValue := { quotedString := v_nonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "uri", paramValue := { quotedString := v_uri } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "response", paramValue := { quotedString := v_response } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "algorithm", paramValue := { tokenOrHost := "md5" } }); // algorithm is not enclosed to " characters v_digestResponse := f_addParameter(v_digestResponse, { id := "cnonce", paramValue := { quotedString := v_cnonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "qop", paramValue := { tokenOrHost := v_qop } }); // qop v_digestResponse := f_addParameter(v_digestResponse, { id := "nc", paramValue := { tokenOrHost := cl_nonceCount } }); // nonceCount if (v_opaque != "") { v_digestResponse := f_addParameter(v_digestResponse, { id := "opaque", paramValue := { quotedString := v_opaque } }); // already enclosed to " characters } v_result := {digestResponse := v_digestResponse}; return v_result; } /** * @desc Function to calculate credentials for request that has an empty entity body such as a REGISTER message. NO RESPONSE value to cause an error! * @param p_userprofile to get important parameters * @param p_method (can be "REGISTER", "INVITE",....) * @param p_challenge parameter from 4xx response * @return Credentials field * @verdict */ function f_calculatecCredentials_wo_response( in SipUserProfile p_userprofile, in charstring p_method, in CommaParam_List p_challenge ) return Credentials { var Credentials v_result; var charstring v_nonce := ""; var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265); // RFC 2617 3.2.2 username: // The name of user in the specified realm. var charstring v_username := p_userprofile.privUsername; var charstring v_realm; // RFC 2617 3.2.2.2 passwd: // A known shared secret, the password of user of the specified // username. var charstring v_passwd := p_userprofile.passwd; var charstring v_algorithm; // a new pseudo-random cnonce value is used every time // that assumes it is only used once const charstring cl_nonceCount := "00000001"; var charstring v_qop := p_userprofile.qop; var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain; // MD5 hash of empty entity body. const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e"; var charstring v_response; var charstring v_opaque; var CommaParam_List v_digestResponse := {}; // extract nonce, realm, algorithm, and opaque from challenge v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce"); v_realm := f_extractParamValueFromChallenge(p_challenge, "realm"); v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm"); v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque"); // calculate a digest response for the Authorize header v_response := fx_calculateDigestResponse(v_nonce, v_cnonce, v_username, v_realm, v_passwd, v_algorithm, cl_nonceCount, p_method, v_qop, v_uri, cl_hEntity); v_digestResponse := f_addParameter(v_digestResponse, { id := "username", paramValue := { quotedString := v_username } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "realm", paramValue := { quotedString := v_realm } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "nonce", paramValue := { quotedString := v_nonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "uri", paramValue := { quotedString := v_uri } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "algorithm", paramValue := { tokenOrHost := "md5" } }); // algorithm is not enclosed to " characters v_digestResponse := f_addParameter(v_digestResponse, { id := "cnonce", paramValue := { quotedString := v_cnonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "qop", paramValue := { tokenOrHost := v_qop } }); // qop v_digestResponse := f_addParameter(v_digestResponse, { id := "nc", paramValue := { tokenOrHost := cl_nonceCount } }); // nonceCount if (v_opaque == "") { v_digestResponse := f_addParameter(v_digestResponse, { id := "opaque", paramValue := { quotedString := v_opaque } }); // already enclosed to " characters } v_result := {digestResponse := v_digestResponse}; return v_result; } /** * @desc Function to calculate credentials for response 401 - WWW-Authorization * @param p_qop of the peer UE (alternatively ) * @param p_authorization parameter from 1st REGISTER request * @return Credentials field * @verdict */ function f_calculatecChallenge_forWWWAuthorizationBody( in charstring p_qop, in Authorization p_authorization ) return Challenge { var CommaParam_List v_challenge; if (ischosen(p_authorization.body[0].digestResponse)) { v_challenge := p_authorization.body[0].digestResponse; } else { v_challenge := p_authorization.body[0].otherResponse.authParams; } return (f_calculatecChallenge_forWWWAuthorization(p_qop, v_challenge)); } /** * @desc Function to calculate credentials for response 401 - WWW-Authorization * @param p_qop of the peer UE (alternatively ) * @param p_challenge parameter from 1st REGISTER request * @return Credentials field * @verdict */ function f_calculatecChallenge_forWWWAuthorization( in charstring p_qop, in CommaParam_List p_challenge ) return Challenge { var Challenge v_result; var charstring v_realm; var charstring v_qop := p_qop; v_realm := f_extractParamValueFromChallenge(p_challenge, "realm"); // Construct credentials for an Authorization field of a request. v_result := { digestCln := { { id := "realm", paramValue := { quotedString := v_realm } }, { id := "nonce", paramValue := { quotedString := "0edff6c521cc3f407f2d9e01cf6ed82b" } }, { id := "algorithm", paramValue := { tokenOrHost := PX_AUTH_ALGORITHM } }, // algorithm is not enclosed with " characters { id := "ck", paramValue := { quotedString := "00112233445566778899aabbccddeeff" } }, { id := "ik", paramValue := { quotedString := "ffeeddccbbaa99887766554433221100" } }, // already enclosed to " characters { /** * This directive is optional, but is made so only for backward compatibility with RFC 2069 * it SHOULD be used by all implementations compliant with this version of the Digest scheme */ id := "qop", paramValue := { tokenOrHost := v_qop } } // qop } }; return v_result; } /** * @desc Function to calculate credentials for request that has an empty entity body such as a REGISTER message and at the end put different private name * @param p_userprofile to get important parameters * @param p_method (can be "REGISTER", "INVITE",....) * @param p_challenge parameter from 4xx response * @return Credentials field * @verdict */ function f_calculatecCredentialsAndChangeUserName( in SipUserProfile p_userprofile, in charstring p_method, in CommaParam_List p_challenge ) return Credentials { var Credentials v_result; var charstring v_nonce := ""; var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265); // RFC 2617 3.2.2 username: // The name of user in the specified realm. var charstring v_username := p_userprofile.privUsername; var charstring v_realm; // RFC 2617 3.2.2.2 passwd: // A known shared secret, the password of user of the specified // username. var charstring v_passwd := p_userprofile.passwd; var charstring v_algorithm; // a new pseudo-random cnonce value is used every time // that assumes it is only used once const charstring cl_nonceCount := "00000001"; var charstring v_qop := p_userprofile.qop; var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain; // MD5 hash of empty entity body. const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e"; var charstring v_response; var charstring v_opaque; var CommaParam_List v_digestResponse := {}; // extract nonce, realm, algorithm, and opaque from challenge v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce"); v_realm := f_extractParamValueFromChallenge(p_challenge, "realm"); v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm"); v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque"); // calculate a digest response for the Authorize header v_response := fx_calculateDigestResponse(v_nonce, v_cnonce, v_username, v_realm, v_passwd, v_algorithm, cl_nonceCount, p_method, v_qop, v_uri, cl_hEntity); // Construct credentials for an Authorization field of a request. v_digestResponse := f_addParameter(v_digestResponse, { id := "username", paramValue := { quotedString := "DifferentToPrivateUser" } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "realm", paramValue := { quotedString := v_realm } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "nonce", paramValue := { quotedString := v_nonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "uri", paramValue := { quotedString := v_uri } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "response", paramValue := { quotedString := v_response } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "algorithm", paramValue := { tokenOrHost := "md5" } }); // algorithm is not enclosed to " characters v_digestResponse := f_addParameter(v_digestResponse, { id := "cnonce", paramValue := { quotedString := v_cnonce } }); v_digestResponse := f_addParameter(v_digestResponse, { id := "qop", paramValue := { tokenOrHost := v_qop } }); // qop v_digestResponse := f_addParameter(v_digestResponse, { id := "nc", paramValue := { tokenOrHost := cl_nonceCount } }); if (v_opaque != "") { v_digestResponse := f_addParameter(v_digestResponse, { id := "opaque", paramValue := { quotedString := "" } }); // already enclosed to " characters } v_result := {digestResponse := v_digestResponse}; return v_result; } /** * @desc Function to check if param related to id from CommanParam_List exist containing challenge. * @param p_challenge parameter from 4xx response * @param p_id name of parameter("nonce", "realm", "ck", "ik"...) * @return parameter p_id value */ function f_checkParamValueFromChallengeIfPresent( in CommaParam_List p_challenge, in charstring p_id ) return boolean { var boolean v_result := false; var integer v_len := lengthof(p_challenge); var charstring v_id := fx_putInLowercase(p_id); var integer i; for (i := 0; i < v_len; i := i + 1) { if (fx_putInLowercase(p_challenge[i].id) == v_id) { v_result := true; } } return v_result; } /** * @desc Function to check if tag is present in SemicolonParam_List * @param p_param_l SemicolonParam_List * @return boolean true if tag is present */ function f_checkTagPresent( SemicolonParam_List p_param_l ) runs on SipComponent return boolean { var integer v_numberOfParams; var integer i := 0; v_numberOfParams := lengthof(p_param_l); while (i < v_numberOfParams) { if (fx_putInLowercase(p_param_l[i].id) == c_tagId) { return (true); } i := i + 1; } return (false); } /** * @desc Function to remove a parameter from SemicolonParam_List * @param p_param_l SemicolonParam_List * @return SemicolonParam_List new parameter list */ function f_removeParameter( SemicolonParam_List p_param_l, charstring p_id ) runs on SipComponent return SemicolonParam_List { var integer v_numberOfParams; var integer i := 0; var integer j := 0; var SemicolonParam_List v_newParamList; v_numberOfParams := lengthof(p_param_l); while (i < v_numberOfParams) { if (not fx_putInLowercase(p_param_l[i].id) == p_id) { v_newParamList[j] := p_param_l[i]; j := j + 1; } i := i + 1; } return v_newParamList; } /** * @desc Function to add a parameter to SemicolonParam_List * @param p_param_l SemicolonParam_List * @return SemicolonParam_List new parameter list */ function f_addParameter( SemicolonParam_List p_param_l, GenericParam p_genparam ) return SemicolonParam_List { var SemicolonParam_List v_newParamList := p_param_l; var integer v_numberOfParams := lengthof(p_param_l); v_newParamList[v_numberOfParams] := p_genparam; return v_newParamList; } /** * @desc Function to extract paramValue related to id from CommanParam_List containing challenge. * @param p_challenge parameter from 4xx response * @param p_id name of parameter("nonce", "realm",...) * @return parameter p_id value */ function f_extractParamValueFromChallenge( in CommaParam_List p_challenge, in charstring p_id ) return charstring { var charstring v_result := ""; var integer v_len := lengthof(p_challenge); var charstring v_id := fx_putInLowercase(p_id); var integer i; var charstring v_tmpchar; for (i := 0; i < v_len; i := i + 1) { if (fx_putInLowercase(p_challenge[i].id) == v_id) { if (isvalue(p_challenge[i].paramValue)) { if(ischosen(p_challenge[i].paramValue.quotedString)) { v_result := valueof(p_challenge[i].paramValue.quotedString); } else { v_result := valueof(p_challenge[i].paramValue.tokenOrHost); } } } } if (v_result == "") { if (match(p_id, "algorithm")) { v_result := "MD5"; } else if (match(p_id, "opaque")) { v_result := ""; } else { v_tmpchar := "Cannot acquire value from credentials."; log("*** " & __SCOPE__ &": INFO: Cannot acquire value from credentials ***"); setverdict(inconc); stop; } } return v_result; } /** * @desc Return the updated component variable of via header * @return component variable of via header */ function f_updateViaHeaderAS( in Via p_via ) runs on SipComponent return Via { var Via v_via; var ViaBody_List v_viaBody_List := p_via.viaBody; var integer v_size_via := lengthof(v_viaBody_List); var integer v_size_via_updated := v_size_via + 1; var ViaBody_List v_viaBody_List_updated; var integer i; vc_branch := c_branchCookie & f_getRndTag(); v_viaBody_List_updated[0] := valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile)); // p_viaBody_List_updated[0 ] := vc_request.msgHeader.route.routeBody[0 ] ; for (i := 1; i < v_size_via_updated; i := i + 1) { v_viaBody_List_updated[i] := v_viaBody_List[i - 1]; } v_via.fieldName := p_via.fieldName; v_via.viaBody := v_viaBody_List_updated; return (v_via); } /** * @desc Return the updated component variable of route header * @return component variable of route header */ function f_updateRouteHeaderAS( in Route p_route ) runs on SipComponent return Route { var Route v_route; var RouteBody_List v_routeBody_List := p_route.routeBody; var integer v_size_route := lengthof(v_routeBody_List); var integer v_size_route_updated := v_size_route - 1; var RouteBody_List v_routeBody_List_updated; var integer i; for (i := 0; i < v_size_route_updated; i := i + 1) { v_routeBody_List_updated[i] := v_routeBody_List[i + 1]; } v_route.fieldName := p_route.fieldName; v_route.routeBody := v_routeBody_List_updated; return (v_route); } /** * @desc Return the updated component variable of record route header * @return component variable of record route header */ function f_updateRecordRouteHeaderAS( in template(value) RecordRoute p_recordRoute ) runs on SipComponent return RecordRoute { var RecordRoute v_recordRoute := valueof( m_recordRoute_currIpAddr_params( vc_userprofile, { { "lr", omit } } ) ); var integer v_size_recordRoute := 0; var integer i; if (isvalue(p_recordRoute)) { v_size_recordRoute := lengthof(valueof(p_recordRoute).routeBody); } for (i := 1; i < v_size_recordRoute + 1; i := i + 1) { v_recordRoute.routeBody[i] := valueof(p_recordRoute).routeBody[i - 1]; } return (v_recordRoute); } } // end group ParameterOperations group FieldOperations { /** * @desc function adds "Tag"-parameter in "To"-headerfield * @param p_to To header field that should get a Tag parameter */ function f_addTagInTo( inout To p_to ) runs on SipComponent { f_addParameterTagIfNotPresent(c_tagId, { tokenOrHost := f_getRndTag() }, p_to); } /** * @desc addition of a single parameter in the via header field * @param p_parameter_name name of parameter to be added * @param p_parameter_value value of parameter to be added * @param p_viaBody the via parameter to be extended * @verdict */ function f_addParameterIfNotPresent( in charstring p_parameter_name, in GenValue p_parameter_value, inout ViaBody p_viaBody ) { if (isvalue(p_viaBody.viaParams)) { return; } p_viaBody.viaParams := { { p_parameter_name, p_parameter_value } }; } /** * @desc function to addd a parameter to the "To" header field (if there is not any parameter) * @param p_parameter_name name of the parameter to be added * @param p_parameter_value value of the paramter to be added * @param p_to "To" header field to be extended * @verdict */ function f_addParameterTagIfNotPresent( in charstring p_parameter_name, in GenValue p_parameter_value, inout To p_to ) { if (isvalue(p_to.toParams)) { return; } p_to.toParams := { { p_parameter_name, p_parameter_value } }; } /** * @desc function compares the IP address of two hosts * @param p_host1 hostname * @param p_host2 hostname * @return boolean value that is true if the IP addresses are identical * @verdict */ function f_equivalentHostAddr( in charstring p_host1, in charstring p_host2 ) return boolean { // A DNS server may be used return (fx_getIpAddr(p_host1) == fx_getIpAddr(p_host2)); } /** * @desc function checks if Require contains Precondition * @param p_message (request or response) SIP message to be analysed * @return true if p_id parameter exist */ function f_checkRequirePrecondition( in Request p_message ) { var boolean v_precondition_found; var integer i; if (isvalue(p_message.msgHeader.require)) { v_precondition_found := false; for (i := 0; i < lengthof(p_message.msgHeader.require.optionsTags); i := i + 1) { if (match(p_message.msgHeader.require.optionsTags[i], c_tagPrecond)) { v_precondition_found := true; } } if (not (v_precondition_found)) { setverdict(fail); log("*** " & __SCOPE__ & ": FAIL: precondition not found in Require options list! ***"); } } else { setverdict(fail); log("*** " & __SCOPE__ & ": FAIL: Require options is not present! ***"); } } /** * @desc function checks if P-Charging-Vector contains a particular parameter * @param p_message (request or response) SIP message to be analysed * @param p_id name of parameter * @return true if p_id parameter exist */ function f_checkPChargingVectorHeaderParamId( in Request p_message, charstring p_id ) return boolean { var integer i; if (isvalue(p_message.msgHeader.pChargingVector)) { for (i := 0; i < lengthof(p_message.msgHeader.pChargingVector.chargeParams); i := i + 1) { if (p_message.msgHeader.pChargingVector.chargeParams[i].id == p_id) { return (true); } } } return (false); } /** * @desc function checks if P-Charging-Vector contains a particular parameter * @param p_message (request or response) SIP message to be analysed * @param p_id name of parameter * @return true if p_id parameter exist */ function f_checkPChargingVectorHeaderParamIdResponse( in Response p_message, charstring p_id ) return boolean { var integer i; if (isvalue(p_message.msgHeader.pChargingVector)) { for (i := 0; i < lengthof(p_message.msgHeader.pChargingVector.chargeParams); i := i + 1) { if (p_message.msgHeader.pChargingVector.chargeParams[i].id == p_id) { return true; } } } return (false); } /** * @desc function returns the Host/Port of a given Contact header field * @param p_contact contact header field to be analysed * @return Host/Port record from the contact header field */ function f_getContactUri( in ContactAddress p_contact ) runs on SipComponent return SipUrl { var SipUrl v_SipUrl; if (ischosen(p_contact.addressField.nameAddr)) { v_SipUrl := p_contact.addressField.nameAddr.addrSpec; } else { v_SipUrl := p_contact.addressField.addrSpecUnion; } return (v_SipUrl); } // end f_getContactUri /** * @desc function returns the Host/Port of a given Contact header field * @param p_contact contact header field to be analysed * @return Host/Port record from the contact header field */ function f_getContactAddr( in ContactAddress p_contact ) runs on SipComponent return HostPort { var HostPort v_locAddr; var SipUrl v_SipUrl; if (ischosen(p_contact.addressField.nameAddr)) { v_SipUrl := p_contact.addressField.nameAddr.addrSpec; } else { v_SipUrl := p_contact.addressField.addrSpecUnion; } v_locAddr.host := v_SipUrl.components.sip.hostPort.host; if (isvalue(v_SipUrl.components.sip.hostPort.portField)) { v_locAddr.portField := v_SipUrl.components.sip.hostPort.portField; } else { v_locAddr.portField := c_defaultSipPort; } return (v_locAddr); } // end f_getContactAddr /** * @desc function checks if History-Info-Header of the p_message contains a particular URI * @param p_message (request or response) SIP message to be analysed * @param p_URI name of parameter * @return true if p_URI parameter exist */ function f_checkHeaderInfoURI( in Response p_message, SipUrl p_URI ) return boolean { var integer i; if (isvalue(p_message.msgHeader.historyInfo)) { for (i := 0; i < lengthof(p_message.msgHeader.historyInfo.historyInfoList); i := i + 1) { if (p_message.msgHeader.historyInfo.historyInfoList[i].nameAddr.addrSpec == p_URI) { return (true); } } } return (false); } /** * @desc function returns the Userinfo from a given To header field * @param p_to To header field to be analysed * @return Userinfo from the To header field as a charstring */ function f_getUserfromTo( in To p_to ) runs on SipComponent return charstring { var SipUrl v_SipUrl; if (ischosen(p_to.addressField.nameAddr)) { v_SipUrl := p_to.addressField.nameAddr.addrSpec; } else { v_SipUrl := p_to.addressField.addrSpecUnion; } return (v_SipUrl.components.sip.userInfo.userOrTelephoneSubscriber); } // end f_getUserfromTo /** * @desc function to generate a 32 bits random number as a charstring for tag field * @param p_cSeq_s CSeq parameter used to modify the tag field value * @return tag value */ function f_getRndCallId( ) return charstring { var charstring v_tag_value := fx_rndStr() & fx_rndStr(); // v_tag_value is initialized with a random value with at least 32 bits of randomness // 4294967296 is a 32 bits integer // v_tag_value := int2str(float2int(4294967296.0*rnd()) + loc_CSeq_s.seqNumber ); return (v_tag_value); } /** * @desc function give access to the top element of the Path header field. * @param p_Request SIP message to be analysed * @return NameAddr (e.g. ) or omit */ function f_getPathHeaderTop( inout Request p_Request ) return template(omit) NameAddr { if (isvalue(p_Request.msgHeader.path)) { if (lengthof(p_Request.msgHeader.path.pathValues) > 0) { return (p_Request.msgHeader.path.pathValues[0].nameAddr); } } return (omit); } /** * @desc function updates first element of a Via headerfield list * @param p_viaBody_List address list of a Via header field * @param p_source_address address to be inserted in the top element */ function f_getViaReplyAddr( inout ViaBody_List p_viaBody_List, inout Address4SIP p_source_address ) runs on SipComponent { var ViaBody v_viaBody; // The address to send message shall be updated after getting information // in the Via header fied and according to 18.2.2 v_viaBody := p_viaBody_List[0]; // received parameter has to be addded to the via hader field // Be careful it could be an Host name and not an IP Address // One of the reasons this error can occur is if no DNS server is available. // As a workaround, it is possible to adapt the configuration on the local machine the test // suite is running on (e.g. under Windows the following file could be configured: // C:\WINDOWS\system32\drivers\etc\hosts). // Check if host address can be rosolved if (not f_equivalentHostAddr(valueof(v_viaBody.sentBy.host), valueof(p_source_address.host))) { f_addParameterIfNotPresent(c_receivedId, { tokenOrHost := valueof(p_source_address.host) }, v_viaBody); } if (isvalue(v_viaBody.sentBy.portField)) { p_source_address.portField := valueof(v_viaBody.sentBy.portField); } else { p_source_address.portField := c_defaultSipPort; } } /** * @desc functions give access to an element of the Route header field (record). * @param p_message (request) SIP message to be analysed * @param p_index index of Route record element to be retrieved * @return HostPort value of the Route element or omit */ function f_getRouteHeaderElementAddressFromRequest( in Request p_message, in integer p_index ) return HostPort { if (isvalue(p_message.msgHeader.route)) { if (lengthof(p_message.msgHeader.route.routeBody) > p_index) { return (p_message.msgHeader.route.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort); } } setverdict(fail); return (c_hostport_dummy); } /** * @desc functions give access to an element of the Record-Route header field (record). * @param p_message (request) SIP message to be analysed * @param p_index index of recordRoute record element to be retrieved * @return HostPort value of the Record-Route element or omit */ function f_getRecordRouteHeaderElementAddressFromRequest( in Request p_message, in integer p_index ) return HostPort { if (isvalue(p_message.msgHeader.recordRoute)) { if (lengthof(p_message.msgHeader.recordRoute.routeBody) > p_index) { return (p_message.msgHeader.recordRoute.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort); } } setverdict(fail); return (c_hostport_dummy); } /** * @desc functions give access to an element of the Record-Route header field (record). * @param p_message (response) SIP message to be analysed * @param p_index index of recordRoute record element to be retrieved * @return HostPort value of the Record-Route element or omit */ function f_getRecordRouteHeaderElementAddressFromResponse( in Response p_message, in integer p_index ) return HostPort { if (isvalue(p_message.msgHeader.recordRoute)) { if (lengthof(p_message.msgHeader.recordRoute.routeBody) > p_index) { return (p_message.msgHeader.recordRoute.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort); } } setverdict(fail); return (c_hostport_dummy); } /** * @desc functions give access to an element of the Via header field (record). * @param p_message (request) SIP message to be analysed * @param p_index index of via record element to be retrieved * @return HostPort value of the Via element or omit */ function f_getViaHeaderElementHostPort( in Request p_message, in integer p_index ) return HostPort { if (lengthof(p_message.msgHeader.via.viaBody) > p_index) { return (p_message.msgHeader.via.viaBody[p_index].sentBy); } setverdict(fail); return (c_hostport_dummy); } /** * @desc functions give access to an element of the Via header field (record). * @param p_message (response) SIP message to be analysed * @param p_index index of via record element to be retrieved * @return HostPort value of the Via element or omit */ function f_getViaHeaderElementHostPortResponse( in Response p_message, in integer p_index ) return HostPort { if (lengthof(p_message.msgHeader.via.viaBody) > p_index) { return (p_message.msgHeader.via.viaBody[p_index].sentBy); } setverdict(fail); return (c_hostport_dummy); } /** * @desc function checks indicators if topology hiding (TH) has been applied: - second element in via-header record has tokenized-by parameter * @param p_Request SIP message to be analysed * @return boolean value (true indicate TH, false otherwise) */ function f_topologyHiding( inout Request p_request ) runs on SipComponent return boolean { var GenericParam v_viaParameter; if (lengthof(p_request.msgHeader.via.viaBody) <2 ) { return (false); } v_viaParameter := p_request.msgHeader.via.viaBody[1].viaParams[0]; // second element if (not v_viaParameter.id == "tokenized-by") { return (false); } return (true); } /** * @desc function checks indicators if topology hiding (TH) has been applied: - any element in via-header record has tokenized-by parameter * @param Response SIP message to be analysed * @return boolean value (true indicate TH, false otherwise) */ function f_topologyHidingResponse( inout Response p_response ) runs on SipComponent return boolean { var GenericParam v_viaParameter; var integer i; for (i := 0; i < lengthof(p_response.msgHeader.via.viaBody); i := i + 1) { v_viaParameter := p_response.msgHeader.via.viaBody[i].viaParams[0]; // first parameter if (not v_viaParameter.id == "tokenized-by") { return (false); } } return (true); } group SetHeaders { /** * @desc function for setting of component variables related to message header fields (message type independent: CSeq, contact, via), function uses information from userprofile * @param p_cSeq_s CSeq parameter * @param p_method method name for cSeq header field */ function f_setHeadersGeneral( inout CSeq p_cSeq_s, in charstring p_method ) runs on SipComponent { p_cSeq_s.fieldName := CSEQ_E; p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1; p_cSeq_s.method := p_method; vc_cSeq := p_cSeq_s; vc_contact := valueof(m_Contact(m_SipUrl_contactIpaddr(vc_userprofile))); vc_branch := c_branchCookie & f_getRndTag(); vc_via := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; } // end function f_setHeadersGeneral /** * @desc function for setting of component variables related to message header fields (message type independent: CSeq, contact, via), function uses information from userprofile * @param p_cSeq_s CSeq parameter * @param p_method method name for cSeq header field */ function f_setHeadersACK( ) runs on SipComponent { // vc_requestUri.hostPort := vc_reqHostPort; if (vc_response.statusLine.statusCode >= 200 and vc_response.statusLine.statusCode <= 299) // ref. RFC3261 8.1.1.7 Via { vc_branch := c_branchCookie & f_getRndTag(); } vc_via := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; } // end function f_setHeadersGeneral /** * @desc setting of general and basic Bye header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersBYE( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "BYE"); // cseq, contact, branch, via // vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr }; f_addTagInTo(vc_to); vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersBYE /** * @desc setting of general and basic CANCEL header fields * @param p_cSeq_s */ function f_setHeadersCANCEL( inout CSeq p_cSeq_s ) runs on SipComponent { p_cSeq_s.method := "CANCEL"; // vc_branch := c_branchCookie & f_getRndTag(); // STF 406: CANCEL and ACK should have the same branch as the INVITE vc_via := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; } // end function f_setHeadersCANCEL /** * @desc function sets header field for the next outgoing REGISTER message * @param p_cSeq_s CSeq parameter to be applied * @param p_emergency Set to true in case of emergency */ function f_setHeaders_REGISTER( inout CSeq p_cSeq_s, boolean p_emergency := false ) runs on SipComponent { var SemicolonParam_List v_params := {}; f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via vc_requestUri := { scheme := c_sipScheme, components := { sip := { userInfo := omit, hostPort := { host := vc_userprofile.registrarDomain, portField := omit } } }, urlParameters := omit, headers := omit }; vc_reqHostPort := vc_requestUri.components.sip.hostPort; vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; vc_callIdReg := vc_callId; // remember callId for de-registration vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile))); vc_cancel_To := vc_to; v_params := f_addParameter(v_params, { id := c_tagId, paramValue := { tokenOrHost := f_getRndTag() } }); vc_from := { fieldName := FROM_E, addressField := vc_to.addressField, fromParams := v_params }; if (not vc_firstREGISTER_sent) { if (p_emergency) { v_params := { { "sos", omit } }; vc_contact.contactBody.contactAddresses[0].addressField.addrSpecUnion.urlParameters := v_params; } else { v_params := { { id := c_expiresId, paramValue := { tokenOrHost := c_shortRegistration } } }; vc_contact.contactBody.contactAddresses[0].contactParams := v_params; } } vc_firstREGISTER_sent := true; // f_setHeaders_Register is called in deREGISTER function vc_authorization := { fieldName := AUTHORIZATION_E, body := {f_calculatecCredentials_empty(vc_userprofile)} }; vc_via_REG := vc_via; } // end function setHeaders_REGISTER /** * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER * @verdict */ function f_setHeaders_2ndREGISTER( inout CSeq p_cSeq_s ) runs on SipComponent { var CommaParam_List v_challenge; // Increment CSeq sequence number p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1; vc_cSeq := p_cSeq_s; vc_requestUri := { scheme := c_sipScheme, components := { sip := { userInfo := omit, hostPort := { host := vc_userprofile.registrarDomain, portField := omit } } }, urlParameters := omit, headers := omit }; // new branch tag due to different branch tag in new REGISTER method vc_branch := c_branchCookie & f_getRndTag(); vc_via_REG := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; // Extract challenge and calculate credentials for a response. v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln; // Prepair right answer vc_authorization := { fieldName := AUTHORIZATION_E, body := {f_calculatecCredentials(vc_userprofile, "REGISTER", v_challenge)} }; } // end function f_setHeaders_2ndREGISTER /** * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER NO response in Authorization header to cause an error * @verdict */ function f_setHeaders_2ndREGISTER_wo_response( ) runs on SipComponent { var CommaParam_List v_challenge; vc_branch := c_branchCookie & f_getRndTag(); vc_via_REG := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; if (ischosen(vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge)) // Extract challenge and calculate credentials for a response. { v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams; } else { v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln; } // Increment CSeq sequence number vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1; // Prepair right answer vc_authorization := { fieldName := AUTHORIZATION_E, body := {f_calculatecCredentials_wo_response(vc_userprofile, "REGISTER", v_challenge)} }; } // end function f_setHeaders_2ndREGISTER_wo_response /** * @desc function sets via, cseq and authorization header with different private name for the next outgoing (protected) REGISTER * @verdict */ function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName( ) runs on SipComponent { var CommaParam_List v_challenge; vc_branch := c_branchCookie & f_getRndTag(); vc_requestUri := { scheme := c_sipScheme, components := { sip := { userInfo := omit, hostPort := { host := vc_userprofile.registrarDomain, portField := omit } } }, urlParameters := omit, headers := omit }; vc_via_REG := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; // Extract challenge and calculate credentials for a response. v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams; // Increment CSeq sequence number vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1; // Prepair right answer vc_authorization := { fieldName := AUTHORIZATION_E, body := {f_calculatecCredentialsAndChangeUserName(vc_userprofile, "REGISTER", v_challenge)} }; } // end function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName /** * @desc function sets header fields for the next outgoing REGISTER (de-registration) * @param p_cSeq_s cSeq to be used * @verdict */ function f_setHeaders_deREGISTER( inout CSeq p_cSeq_s ) runs on SipComponent { var SemicolonParam_List v_params := {}; f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via // reset authorization header to not use nonce from registration (otherwise we have to increase nc) vc_authorization := { fieldName := AUTHORIZATION_E, body := {f_calculatecCredentials_empty(vc_userprofile)} }; vc_requestUri := { scheme := c_sipScheme, components := { sip := { userInfo := omit, hostPort := { host := vc_userprofile.registrarDomain, portField := omit } } }, urlParameters := omit, headers := omit }; vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile))); v_params := f_addParameter(v_params, { id := c_tagId, paramValue := { tokenOrHost := f_getRndTag() } }); vc_from := { fieldName := FROM_E, addressField := vc_to.addressField, fromParams := v_params }; vc_contact := { fieldName := CONTACT_E, contactBody := {wildcard := "*"} }; } // end function f_setHeaders_deREGISTER /** * @desc setting of general and basic Invite header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersINVITE( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "INVITE"); // cseq, contact, branch, via vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; if (ischosen(vc_requestUri.components.sip)) { // sip/sips call vc_reqHostPort := vc_requestUri.components.sip.hostPort; } else if (ischosen(vc_requestUri.components.urn)) { // Emergency call vc_reqUrnUri := vc_requestUri.components.urn; } else { log("*** " & __SCOPE__ &": INFO:f_setHeadersINVITE: unsupported field: ", vc_requestUri," ***"); setverdict(fail); } } /** * @desc setting of general and basic Update header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersUPDATE( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "UPDATE"); // cseq, contact, branch, via vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersUPDATE /** * @desc setting of general and basic Message header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersMESSAGE( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "MESSAGE"); // cseq, contact, branch, via vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersMESSAGE /** * @desc setting of general and basic Notify header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersNOTIFY( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "NOTIFY"); // cseq, contact, branch, via vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersNOTIFY /** * @desc setting of general and basic Notify header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersOPTIONS( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "OPTIONS"); // cseq, contact, branch, via vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersOPTIONS /** * @desc setting of general and basic Publish header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersPUBLISH( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "PUBLISH"); // cseq, contact, branch, via // after SUBSCRIBE message callid shall be same // vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersPUBLISH /** * @desc function sets header field for the next outgoing SUBSCRIBE message * @param p_cSeq_s CSeq parameter to be applied */ function f_setHeaders_SUBSCRIBE( inout CSeq p_cSeq_s ) runs on SipComponent { var SemicolonParam_List v_params := {}; f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via vc_requestUri := valueof(m_SipUrl_currDomain(vc_userprofile)); vc_reqHostPort := vc_requestUri.components.sip.hostPort; vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; // store callId from Subscribe message vc_callIdSub := vc_callId; vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile))); vc_cancel_To := vc_to; v_params := f_addParameter(v_params, { id := c_tagId, paramValue := { tokenOrHost := f_getRndTag() } }); vc_from := { fieldName := FROM_E, addressField := vc_to.addressField, fromParams := v_params }; } // end function setHeaders_SUBSCRIBE /** * @desc setting of general and basic Subscribe header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersSUBSCRIBE( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via vc_callId := { fieldName := CALL_ID_E, callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersMESSAGE /** * @desc setting of general and basic REFER header fields in additon to the addresses (To, From, ReqUri) * @param p_cSeq_s */ function f_setHeadersREFER( inout CSeq p_cSeq_s ) runs on SipComponent { f_setHeadersGeneral(p_cSeq_s, "REFER"); // cseq, contact, branch, via // vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr }; vc_cancel_To := vc_to; vc_caller_To := vc_to; vc_caller_From := vc_from; vc_reqHostPort := vc_requestUri.components.sip.hostPort; } // end function f_setHeadersREFER /** * @desc This function reads all necessary headers from the received REGISTER message and generate the tag for the answer * @param p_Request REGISTER that has been received */ function f_setHeadersOnReceiptOfREGISTER( Request p_Request ) runs on SipComponent { f_setHeadersOnReceiptOfRequest(p_Request); vc_callId := p_Request.msgHeader.callId; vc_caller_From := vc_from; f_addTagInTo(vc_to); vc_caller_To := vc_to; vc_requestUri := p_Request.requestLine.requestUri; vc_cancel_To := p_Request.msgHeader.toField; if (isvalue(p_Request.msgHeader.contact) and (not ischosen(p_Request.msgHeader.contact.contactBody.wildcard))) { vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); } // update callee information and pick up tag if the call need to be canceled vc_callee_To := { fieldName := TO_E, addressField := vc_caller_From.addressField, toParams := vc_caller_From.fromParams }; vc_callee_From := { fieldName := FROM_E, addressField := vc_caller_To.addressField, fromParams := vc_caller_To.toParams }; if (isvalue(p_Request.msgHeader.authorization)) { vc_authorization := valueof(p_Request.msgHeader.authorization); } } // end f_setHeadersOnReceiptOfREGISTER /** * @desc This function reads all necessary headers from the received SUBSCRIBE message and generate the tag for the answer * @param p_Request SUBSCRIBE that has been received */ function f_setHeadersOnReceiptOfSUBSCRIBE( Request p_Request ) runs on SipComponent { f_setHeadersOnReceiptOfRequest(p_Request); vc_callId := p_Request.msgHeader.callId; vc_caller_From := vc_from; f_addTagInTo(vc_to); vc_caller_To := vc_to; vc_requestUri := p_Request.requestLine.requestUri; vc_cancel_To := p_Request.msgHeader.toField; if (isvalue(p_Request.msgHeader.contact)) { vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); } // update callee information and pick up tag if the call need to be canceled vc_callee_To := { fieldName := TO_E, addressField := vc_caller_From.addressField, toParams := vc_caller_From.fromParams }; vc_callee_From := { fieldName := FROM_E, addressField := vc_caller_To.addressField, fromParams := vc_caller_To.toParams }; } // end f_setHeadersOnReceiptOfSUBSCRIBE function f_setHeadersOnReceiptOfREFER( Request p_Request ) runs on SipComponent { f_setHeadersOnReceiptOfRequest(p_Request); vc_requestUri := p_Request.requestLine.requestUri; vc_cancel_To := p_Request.msgHeader.toField; if (isvalue(p_Request.msgHeader.contact)) { vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); } // update callee information and pick up tag if the call need to be canceled vc_callee_To := { fieldName := TO_E, addressField := vc_caller_From.addressField, toParams := vc_caller_From.fromParams }; vc_callee_From := { fieldName := FROM_E, addressField := vc_caller_To.addressField, fromParams := vc_caller_To.toParams }; } // end f_setHeadersOnReceiptOfREFER /** * @desc function reads all necessary headers from the received INVITE message and generate the tag for the answer * @param p_Request received INVITE message * @verdict */ function f_setHeadersOnReceiptOfINVITE( Request p_Request ) runs on SipComponent { var integer i, j; var integer v_length; f_setHeadersOnReceiptOfRequest(p_Request); vc_callId := p_Request.msgHeader.callId; vc_requestUri2 := p_Request.requestLine.requestUri; vc_cancel_To := p_Request.msgHeader.toField; f_addTagInTo(vc_to); vc_caller_From := vc_from; vc_caller_To := vc_to; if (isvalue(p_Request.msgHeader.contact)) { vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]); } // update callee information and pick up tag if the call need to be canceled vc_callee_To := { fieldName := TO_E, addressField := vc_caller_From.addressField, toParams := vc_caller_From.fromParams }; vc_callee_From := { fieldName := FROM_E, addressField := vc_caller_To.addressField, fromParams := vc_caller_To.toParams }; if (isvalue(p_Request.msgHeader.privacy)) { vc_privacy := p_Request.msgHeader.privacy; } if (isvalue(p_Request.messageBody)) { // cleaning of attributes before assignment if (isvalue(vc_sdp_remote.media_list)) { v_length := lengthof(vc_sdp_remote.media_list); for (i := 0; i < v_length; i := i + 1) { if (isvalue(vc_sdp_remote.media_list[i].attributes)) { vc_sdp_remote.media_list[i].attributes := omit; } } } // save SDP if present if (ischosen(p_Request.messageBody.sdpMessageBody)) { vc_sdp_remote := p_Request.messageBody.sdpMessageBody; vc_sdp_remote_is_valid := true; f_prepare_SDP_answer(); } // save XML if present if (ischosen(p_Request.messageBody.xmlBody)) { vc_xml_remote := p_Request.messageBody.xmlBody; } if (ischosen(p_Request.messageBody.mimeMessageBody)) { for (j := 0; j < lengthof(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) { if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) { vc_sdp_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody; vc_sdp_remote_is_valid := true; f_prepare_SDP_answer(); } if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) { vc_xml_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody; } } } } if (isvalue(p_Request.msgHeader.supported.optionsTags)) { for (i := lengthof(p_Request.msgHeader.supported.optionsTags); i > 0; i := i - 1) { if (p_Request.msgHeader.supported.optionsTags[i - 1] == "100rel") { vc_supported_100rel := true; } if (p_Request.msgHeader.supported.optionsTags[i - 1] == "precondition") { vc_supported_precondition := true; } } } } // end f_setHeadersOnReceiptOfINVITE /** * @desc function reads header field of a received BYE message * @param p_Request received BYE */ function f_setHeadersOnReceiptOfBYE( Request p_BYE_Request ) runs on SipComponent { f_setHeadersOnReceiptOfRequest(p_BYE_Request); vc_callId := p_BYE_Request.msgHeader.callId; } // end f_setHeadersOnReceiptOfBYE /** * @desc function reads header field from an incoming Request message * @param p_Request received Request message */ function f_setHeadersOnReceiptOfRequest( Request p_Request ) runs on SipComponent { vc_request := p_Request; vc_callId := p_Request.msgHeader.callId; vc_cSeq := valueof(p_Request.msgHeader.cSeq); // CSeq is mandatory vc_iut_CSeq := p_Request.msgHeader.cSeq; vc_from := p_Request.msgHeader.fromField; vc_caller_From := p_Request.msgHeader.fromField; vc_to := p_Request.msgHeader.toField; vc_caller_To := p_Request.msgHeader.toField; vc_via := p_Request.msgHeader.via; // update sent_label according to received via header field f_getViaReplyAddr(vc_via.viaBody, vc_sent_label); // Catch route vc_boo_recordRoute := false; // add tag field into To header if tag is not present if (not (isvalue(p_Request.msgHeader.toField.toParams))) { vc_to.toParams := { { id := c_tagId, paramValue := { tokenOrHost := f_getRndTag() } } }; vc_caller_To := vc_to; } if (isvalue(p_Request.msgHeader.recordRoute.fieldName)) {//Due to ES 201 873-1/C.3.3 Better to check if fieldName of Record Route is present vc_boo_recordRoute := true; vc_recordRoute := p_Request.msgHeader.recordRoute; } } // end f_setHeadersOnReceiptOfRequest /** * @desc functions reads header fields from an incoming Response message * @param p_cSeq * @param p_response received response message * @verdict */ function f_setHeadersOnReceiptOfResponse( Response p_response ) runs on SipComponent { var integer i, j, v_nbroute; var template(omit) Contact v_contact; // only for local purpose vc_response := p_response; // vc_cSeq := p_cSeq; //must not save global c_seq because it can overwrite temporary cSeq vc_to := p_response.msgHeader.toField; vc_from := p_response.msgHeader.fromField; vc_caller_To := vc_to; vc_caller_From := vc_from; if (isvalue(p_response.msgHeader.contact)) { v_contact := p_response.msgHeader.contact; if (ischosen(v_contact.contactBody.contactAddresses)) { vc_reqHostPort := f_getContactAddr(valueof(v_contact.contactBody.contactAddresses[0])); vc_requestUri := f_getContactUri(valueof(v_contact.contactBody.contactAddresses[0])); } } else { if (ischosen(vc_to.addressField.addrSpecUnion.components.sip)) { // sip/sips call vc_reqHostPort := vc_to.addressField.addrSpecUnion.components.sip.hostPort; } else if (ischosen(vc_to.addressField.addrSpecUnion.components.urn)) { // Emergency call vc_reqUrnUri := vc_to.addressField.addrSpecUnion.components.urn; } else { log("*** f_setHeadersOnReceiptOfResponse: INFO: unsupported field: ", vc_to, " ***"); setverdict(fail); } vc_requestUri := vc_to.addressField.addrSpecUnion; } vc_callee_To := { fieldName := TO_E, addressField := vc_caller_From.addressField, toParams := vc_caller_From.fromParams }; vc_callee_From := { fieldName := FROM_E, addressField := vc_caller_To.addressField, fromParams := vc_caller_To.toParams }; vc_via := p_response.msgHeader.via; // Route Management if (isvalue(p_response.msgHeader.recordRoute)) { vc_recordRoute := p_response.msgHeader.recordRoute; v_nbroute := lengthof(vc_recordRoute.routeBody); // copy and reverse the order of the routes in route header for (i := 0; i <= (v_nbroute - 1); i := i + 1) { j := v_nbroute - 1 - i; vc_route.routeBody[j] := vc_recordRoute.routeBody[i]; } vc_route.fieldName := ROUTE_E; vc_boo_recordRoute := true; vc_boo_route := true; } else { vc_boo_recordRoute := false; vc_boo_route := false; } // extentions due to new fields in PRACK and UPDATE messages if (isvalue(p_response.msgHeader.rSeq)) { vc_rAck := { fieldName := RACK_E, responseNum := valueof(p_response.msgHeader.rSeq.responseNum), seqNumber := valueof(p_response.msgHeader.cSeq.seqNumber), method := valueof(p_response.msgHeader.cSeq.method) }; } // extentions due to new HistoryInfo fields 180 or 200OK messages if (isvalue(p_response.msgHeader.historyInfo)) { vc_historyInfoList := valueof(p_response.msgHeader.historyInfo.historyInfoList); vc_history_is_valid := true; } else { vc_history_is_valid := false; } // sdpMessageBody answer if (isvalue(p_response.messageBody)) { if (ischosen(p_response.messageBody.sdpMessageBody)) { vc_sdp_remote := p_response.messageBody.sdpMessageBody; vc_sdp_remote_is_valid := true; } if (ischosen(p_response.messageBody.xmlBody)) { vc_xml_remote := p_response.messageBody.xmlBody; } if (ischosen(p_response.messageBody.mimeMessageBody)) { for (j := 0; j < lengthof(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) { if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) { vc_sdp_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody; } if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) { vc_xml_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody; } } } } } // end function f_setHeadersOnReceiptOfResponse /** * @desc functions reads ServiceRoute header field from an incoming 200 Response message in registration * @param p_cSeq * @param p_response received response message */ function f_getServiceRouteMapIntoRouteInRegistration( Response p_response ) runs on SipComponent { var integer i, j, v_nbroute; var template(omit) ServiceRoute v_serviceRoute; // Route Management if (isvalue(p_response.msgHeader.serviceRoute.fieldName)) {////Due to ES 201 873-1/C.3.3 Better to check if fieldName of Record Route is present v_serviceRoute := p_response.msgHeader.serviceRoute; v_nbroute := lengthof(v_serviceRoute.routeBody); // copy and reverse the order of the routes in route header for (i := 0; i <= (v_nbroute - 1); i := i + 1) { j := v_nbroute - 1 - i; vc_route.routeBody[j] := v_serviceRoute.routeBody[i]; } vc_route.fieldName := ROUTE_E; vc_route_REG := vc_route; vc_boo_route := true; } } // end function f_getServiceRouteMapIntoRouteInRegistration /** * @desc functions reads Route header field from an incoming Request message and generate RecordRoute * @param p_cSeq * @param p_request received request message */ function f_getRouteMapIntoRecordRoute( Request p_request ) runs on SipComponent { var integer i, j, v_nbroute; var template(omit) Route v_route; // Route Management if (isvalue(p_request.msgHeader.route)) { v_route := p_request.msgHeader.route; v_nbroute := lengthof(v_route.routeBody); // copy and reverse the order of the routes in route header for (i := 0; i <= (v_nbroute - 1); i := i + 1) { j := v_nbroute - 1 - i; vc_recordRoute.routeBody[j] := v_route.routeBody[i]; } vc_recordRoute.fieldName := RECORD_ROUTE_E; vc_boo_recordRoute := true; } } // end function f_getRouteMapIntoRecordRoute } // end group SetHeaders } // end group FieldOperations group SDPOperations { /** * @desc check if message body include SDP attribute (2nd parameter) for any media */ function f_check_attribute( in SDP_Message p_sdp, in template SDP_attribute p_attribute ) runs on SipComponent return boolean { var integer i, j; if (isvalue(p_sdp.media_list)) { for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) { if (isvalue(p_sdp.media_list[j].attributes)) { for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) { if (match(p_sdp.media_list[j].attributes[i], p_attribute)) { return (true); } } } } } if (isvalue(p_sdp.attributes)) { for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) { if (match(p_sdp.attributes[j], p_attribute)) { return (true); } } } return (false); } /** * @desc check if message body include SDP (session level) attribute (2nd parameter) for any media */ function f_check_session_attribute( in SDP_Message p_sdp, in template SDP_attribute p_attribute ) runs on SipComponent return boolean { var integer j; if (isvalue(p_sdp.attributes)) { for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) { if (match(p_sdp.attributes[j], p_attribute)) { return (true); } } } return (false); } /** * @desc identify an SDP direction attribute (session or first media attribute) in a SDP message and return its answer value * @param p_sdp the SDP message that has been received * @param p_attribute incoming SDP attribute that need to be used for the SDP direction (answer) * @return the new attribute (to be send out) derived from the incoming SDP value * @verdict */ function f_get_attribute_answer( in SDP_Message p_sdp, in template SDP_attribute p_attribute ) runs on SipComponent return SDP_attribute { var integer i, j; var template SDP_attribute v_attribute := p_attribute; // check if the selected attribute is included in the SDP offer (session attributes) if (isvalue(p_sdp.attributes)) { for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) { if (match(p_sdp.attributes[j], p_attribute)) { v_attribute := p_sdp.attributes[j]; } } } else // check if the selected attribute is included in the SDP offer (any of the media attributes) { if (isvalue(p_sdp.media_list)) { for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) { if (isvalue(p_sdp.media_list[j].attributes)) { for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) { if (match(p_sdp.media_list[j].attributes[i], p_attribute)) { v_attribute := p_sdp.media_list[j].attributes[i]; } } } } } } select (valueof(v_attribute)) { case (mw_attribute_sendonly) { return (valueof(m_attribute_recvonly)); } 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 p_loc_sdp, in template SDP_bandwidth p_loc_bandw ) runs on SipComponent return boolean { var integer i, j; if (isvalue(p_loc_sdp.bandwidth)) { for (j := 0; j < lengthof(p_loc_sdp.bandwidth); j := j + 1) { if (match(p_loc_sdp.bandwidth[j], p_loc_bandw)) { return (true); } } } if (isvalue(p_loc_sdp.media_list)) { for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) { if (isvalue(p_loc_sdp.media_list[j].bandwidth)) { for (i := 0; i < lengthof(p_loc_sdp.media_list[j].bandwidth); i := i + 1) { if (match(p_loc_sdp.media_list[j].bandwidth[i], p_loc_bandw)) { return (true); } } } } } return (false); } /** * @desc check if message body include SDP media (2nd parameter) */ function f_check_media( in SDP_Message p_loc_sdp, in template(present) SDP_media_desc p_loc_media ) runs on SipComponent return boolean { var integer j; if (isvalue(p_loc_sdp.media_list)) { for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) { if (match(p_loc_sdp.media_list[j].media_field.transport, p_loc_media.media_field.transport) and match(p_loc_sdp.media_list[j].media_field.fmts, p_loc_media.media_field.fmts)) { return (true); } } } return (false); } /** * @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 p_loc_sdp ) runs on SipComponent return boolean { if (f_check_attribute(p_loc_sdp, mw_attribute_des) or f_check_attribute(p_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 p_loc_sdp ) runs on SipComponent return boolean { if (f_check_attribute(p_loc_sdp, mw_attribute_sendonly) or f_check_attribute(p_loc_sdp, mw_attribute_recvonly) or f_check_attribute(p_loc_sdp, mw_attribute_sendrecv) or f_check_attribute(p_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 p_loc_sdp, integer p_loc_codec ) runs on SipComponent return boolean { var SDP_media_desc v_media := f_prepare_media(p_loc_sdp, p_loc_codec); if (vc_sdp_remote.media_list[0].media_field.media != v_media.media_field.media) { return false; } if (vc_sdp_remote.media_list[0].media_field.transport != v_media.media_field.transport) { return false; } if (vc_sdp_remote.media_list[0].media_field.fmts != v_media.media_field.fmts) { return false; } return true; } /** * @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 ) { var integer i; var integer v_mn; if (isvalue(p_sdp.media_list)) { v_mn := lengthof(p_sdp.media_list[0].attributes); for (i := 0; i < v_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 := v_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 ) { var integer v_mn; if (isvalue(p_sdp.media_list)) { v_mn := lengthof(p_sdp.media_list[0].attributes); p_sdp.media_list[0].attributes[v_mn] := p_att; } } /** * @desc append new media to the existing media list in SDP */ function f_append_media( inout SDP_Message p_loc_SDP, template(value) SDP_media_desc p_loc_media ) { var integer v_mn := lengthof(p_loc_SDP.media_list); p_loc_SDP.media_list[v_mn] := valueof(p_loc_media); } /** * @desc repare media/attribute lines */ function f_prepare_media( integer p_loc_sdp, integer p_loc_codec ) runs on SipComponent return SDP_media_desc { var SDP_attribute_rtpmap_codec v_codecs[32] := { {"PCMU", "8000", omit}, {"GSM", "8000", omit}, {"G723", "8000", omit}, {"DVI4", "8000", omit}, {"DVI4", "16000", omit}, {"LPC", "8000", omit}, {"PCMA", "8000", omit}, {"G722", "8000", omit}, {"L16", "44100", "2"}, {"L16", "44100", omit}, {"QCELP", "8000", omit}, {"CN","8000", omit}, {"MPA", "90000", omit}, {"G728", "8000", omit}, {"DVI4", "11025", omit}, {"DVI4", "22050", omit}, {"G729", "8000", omit}, {"G726-40", "8000", omit}, {"G726-32", "8000", omit}, {"G726-24", "8000", omit}, {"G726-16", "8000", omit}, {"G726D", "8000", omit}, {"G726E", "8000", omit}, {"GSM-EFR", "8000", omit}, {"CelB", "90000", omit}, {"JPEG", "90000", omit}, {"Nv", "90000", omit}, {"H261", "90000", omit}, {"MPV", "90000", omit}, {"MP2T" ,"90000", omit}, {"H263", "90000", omit}, {"H263-1998", "90000", omit}}; 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 < p_loc_codec or p_loc_codec < 1) { log("*** " & __SCOPE__ & ": INFO: Unexpected SDP variant ***"); setverdict(inconc); return (v_media); } if (p_loc_sdp == 1) { } else if (p_loc_sdp == 2) { v_media.media_field.fmts := {PX_SIP_SDP_DYN}; // { "98", "0" }; v_media.attributes := { { rtpmap := { payload_type := PX_SIP_SDP_DYN, codec := v_codecs[p_loc_codec - 1] } } }; } else if (p_loc_sdp == 3) { v_media.media_field.fmts := {"8"}; } else if (p_loc_sdp == 4) { v_media.media_field.fmts := {"99", "8"}; v_media.attributes := { { rtpmap := { payload_type := "99", codec := v_codecs[p_loc_codec - 1] } } }; } else if (p_loc_sdp == 5) { v_media.media_field.media := "image"; v_media.media_field.transport := "udptl"; v_media.media_field.fmts := {"t38"}; } else if (p_loc_sdp == 6) { v_media.media_field.media := "image"; v_media.media_field.transport := "tcptl"; v_media.media_field.fmts := {"t38"}; } else { log("*** " & __SCOPE__ & ": INFO: Unexpected SDP variant ***"); setverdict(inconc); } return (v_media); } /** * @desc repare media/attribute lines */ function f_prepare_SDP( integer p_loc_sdp, integer p_loc_codec ) runs on SipComponent { vc_sdp_local.media_list := {f_prepare_media(p_loc_sdp, p_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 v_mn, v_cn := 0, i, j, k := 0; var charstring v_PT; var SDP_attribute_rtpmap_codec v_rtpmap := { "", "", omit}; 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 v_mn := lengthof(vc_sdp_remote.media_list); for (i := 0; i < v_mn; i := i + 1) { // for every single media if (isvalue(vc_sdp_remote.media_list[i].attributes)) { v_cn := lengthof(vc_sdp_remote.media_list[i].attributes); } if (lengthof(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 < v_cn; j := j + 1) { if (ischosen(vc_sdp_remote.media_list[i].attributes[j].rtpmap)) { if (v_PT == vc_sdp_remote.media_list[i].attributes[j].rtpmap.payload_type) { v_rtpmap := vc_sdp_remote.media_list[i].attributes[j].rtpmap.codec; v_mediaAttributes[k] := {rtpmap := {v_PT, 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 (isvalue(vc_sdp_local.media_list[i].attributes)) { v_cn := lengthof(vc_sdp_local.media_list[i].attributes); for (j := 0; j < v_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"; } } else if ( // b) copy/keep SDP_attribute_des (keep strength, invert tags if applicable) 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"; } } else if ( // c) simplification: assume no SDP_attribute_conf ischosen(vc_sdp_local.media_list[i].attributes[j].conf) ) { // 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 := lengthof(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; // {}; } } /** * @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 * @verdict */ function f_SIP_modMediaDirection( integer p_medianum, template(value) SDP_attribute p_direction ) runs on SipComponent { 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); // if more than one codec, select the first one v_mn := lengthof(vc_sdp_local.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 (not (p_medianum > v_mn)) { v_mn := p_medianum; } } // handling of media list elements for (i := 0; i < v_mn; i := i + 1) { v_cn := 0; // initialize the number of attributes of the media list entry if (isvalue(vc_sdp_local.media_list)) // media_list is optional { // log("vc_sdp_local.media_list[i ] ",vc_sdp_local.media_list[i ] ); if (isvalue(vc_sdp_local.media_list[i].attributes)) { v_cn := lengthof(vc_sdp_local.media_list[i].attributes); } v_set_direction := false; // if (lengthof(vc_sdp_local.media_list[i ] .media_field.fmts)>1) // select the first one 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(value) SDP_attribute p_direction ) runs on SipComponent { var boolean v_set_direction := false; var integer v_mn := 0, i := 0; if (isvalue(vc_sdp_local.attributes)) { v_mn := lengthof(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)) { vc_sdp_local.attributes[i] := valueof(p_direction); v_set_direction := true; } } if (not v_set_direction) // if not sent before { 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(value) SDP_attribute p_direction_in, template(value) SDP_attribute p_direction_out ) runs on SipComponent { var template(value) SDP_attribute v_direction_out := p_direction_out; // check incoming SDP attribute if (not (isvalue(vc_request.messageBody) and (f_check_attribute(vc_request.messageBody.sdpMessageBody, p_direction_in)))) { if (match(valueof(p_direction_in), 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("*** " &__SCOPE__& ": INFO: no direction attributes with expectation: ", p_direction_in, " ***"); } else { setverdict(fail); } } else { setverdict(pass); log("*** " &__SCOPE__& ": INFO: attribute found in message body ***"); } if (not isbound(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(value) SDP_attribute p_direction_in, template(value) SDP_attribute p_direction_out ) runs on SipComponent { var template(value) SDP_attribute v_direction_out := p_direction_out; // check incoming SDP attribute if (not (isvalue(vc_response.messageBody) and (f_check_attribute(vc_response.messageBody.sdpMessageBody, p_direction_in)))) { if (match(valueof(p_direction_in), 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("*** " &__SCOPE__& ": INFO: no direction attributes with expectation: ", p_direction_in, " ***"); } else { setverdict(fail); } } else { setverdict(pass); log("*** " &__SCOPE__& ": INFO: attribute found in message body ***"); } if (not isbound(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(value) SDP_attribute p_direction_in, template(value) SDP_attribute p_direction_out ) runs on SipComponent { var template(value) SDP_attribute v_direction_out := p_direction_out; // check incoming SDP attribute if (not (isvalue(vc_request.messageBody) and (f_check_session_attribute(vc_request.messageBody.sdpMessageBody, p_direction_in)))) { if (match(valueof(p_direction_in), mw_attribute_sendrecv) 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("*** " &__SCOPE__& ": INFO: no direction attributes with expectation: ", p_direction_in, " ***"); } else { setverdict(fail); } } if (not isbound(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(value) SDP_attribute p_direction_in, template(value) SDP_attribute p_direction_out ) runs on SipComponent { var template(value) SDP_attribute v_direction_out := p_direction_out; // check incoming SDP attribute if (not (isvalue(vc_response.messageBody) and (f_check_session_attribute(vc_response.messageBody.sdpMessageBody, p_direction_in)))) { if (match(valueof(p_direction_in), mw_attribute_sendrecv) 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("*** " &__SCOPE__& ": INFO: no direction attributes with expectation: ", p_direction_in, " ***"); } else { setverdict(fail); } } if (not isbound(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 (isvalue(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 := lengthof(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 (isvalue(vc_sdp_remote.media_list[i].attributes)) { v_cn := lengthof(vc_sdp_remote.media_list[i].attributes); } if (lengthof(vc_sdp_remote.media_list[i].attributes) > 0) { // select the first one for (j := 0; j < lengthof(vc_sdp_remote.media_list[i].attributes); j := j + 1) { 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; } } } } } return v_result; } /** * @desc copy media/attribute lines from remote to local SDP variable */ function f_copy_SDP( ) runs on SipComponent { if (isvalue(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 (isvalue(vc_sdp_remote.bandwidth)) { vc_sdp_local.bandwidth := vc_sdp_remote.bandwidth; } else { vc_sdp_local.bandwidth := {}; } if (isvalue(vc_sdp_remote.media_list)) { // // cleaning of media before assignment // if (isvalue(vc_sdp_local.media_list)) // { // for (var integer i:=0; i value v_request sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfREGISTER(v_request); } [] tc_wait.timeout { setverdict(fail); f_componentStop(); } } } /** * @desc function awaits SUBSCRIBE * @param p_register expected SUBSCRIBE request */ function f_awaitingSUBSCRIBE( in template(present) SUBSCRIBE_Request p_subscribe := ? ) runs on SipComponent { var SUBSCRIBE_Request v_request; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_subscribe) -> value v_request sender vc_sent_label { tc_wait.stop; 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(present) REGISTER_Request p_register := ?, in boolean p_reply ) runs on SipComponent { var REGISTER_Request v_request; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_register) -> value v_request sender vc_sent_label { tc_wait.stop; vc_request := v_request; f_setHeadersOnReceiptOfREGISTER(v_request); // Answer to the Request if (p_reply) { f_send200OK(); } } [] tc_wait.timeout { setverdict(fail); 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; alt { [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); setverdict(pass); } } } // end awaitingOkResponse /** * @desc Function waiting for a response * @param p_Response expected response message */ function f_awaitingResponse( in template(present) Response p_Response := ? ) runs on SipComponent { tc_resp.start; a_awaitingResponse(p_Response); } // end f_awaitingResponse altstep a_awaitingResponse( in template(present) Response p_Response := ? ) runs on SipComponent { [] SIPP.receive(p_Response) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // setverdict(pass) } } // end f_awaitingResponse /** * @desc Function waiting for a response, repeat if 100 Trying is received * @param p_Response expected response message */ function f_awaitingResponseIgnore100Trying( in template(present) Response p_Response := ? ) runs on SipComponent { tc_resp.start; alt { [] SIPP.receive(p_Response) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // setverdict(pass) } [] SIPP.receive(mw_Response_Base(c_statusLine100, vc_callId, vc_cSeq)) -> value vc_response { repeat; } } } // end f_awaitingResponseIgnore100Trying /** * @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(present) Response p_Response := ? ) runs on SipComponent { tc_resp.start; alt { [] SIPP.receive(p_Response) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); LibSip_Steps.f_setHeadersACK(); f_SendACK(m_ACK_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)); setverdict(pass); } } } // end f_awaitingResponse /** * @desc Function waiting for a response * @param p_Response expected response message */ function f_awaitingResponsePassOnTimeout( in template(present) Response p_Response := ? ) runs on SipComponent { tc_resp.start; alt { [] SIPP.receive(p_Response) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); vc_boo_response := true; // setverdict(pass) } [] tc_resp.timeout { vc_boo_response := false; // setverdict (pass) } } } // end f_awaitingResponsePassOnTimeout /** * @desc Function waiting for a 200 OK response * @param p_cSeq_s current cSeq expectation */ function f_awaitingOkResponseAndNOTIFY_sendReply( inout CSeq p_cSeq_s, in template(present) NOTIFY_Request p_MSG := ? ) runs on SipComponent { var boolean v_received_OK := false; var boolean v_received_NOTIFY := false; var NOTIFY_Request v_MSG; tc_resp.start; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; vc_subscribed := true; f_setHeadersOnReceiptOfResponse(vc_response); v_received_OK := true; setverdict(pass); if (not (v_received_NOTIFY)) { repeat; } } [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_getRouteMapIntoRecordRoute(v_MSG); f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the NOTIFY f_send200OK(); v_received_NOTIFY := true; if (not (v_received_OK)) { repeat; } } } } // end f_awaitingOkResponseAndNOTIFY_sendReply /** * @desc await INFO request reply with 200 OK */ function f_awaitingINFO_sendReply( in template(value) INFO_Request p_info ) runs on SipComponent { var INFO_Request v_request; tc_wait.start(PX_SIP_TWAIT); alt { [] 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(present) 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(present) 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(present) 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; } [] tc_wait.timeout { vc_boo_request := false; } } } // end f_awaitingInviteRequest /** * @desc function awaiting ACK request */ function f_awaitingACK( in template(present) ACK_Request p_ACK := ? ) runs on SipComponent { f_awaitingACK_setHeaders(p_ACK, false); } // end f_awaitingACK /** * @desc function awaiting ACK request */ function f_awaitingACK_setHeaders( in template(present) ACK_Request p_ACK := ?, in boolean p_setHeaders ) runs on SipComponent { var ACK_Request v_ACK_Request; tc_ack.start; alt { [] SIPP.receive(p_ACK) -> value v_ACK_Request { tc_ack.stop; if (p_setHeaders) { f_setHeadersOnReceiptOfRequest(v_ACK_Request); } } } } // end f_awaitingACK_setHeaders /** * @desc function awaiting BYE and sending 200OK response * @param p_BYE expected BYE */ function f_awaitingBYE( in template(present) BYE_Request p_BYE := ? ) runs on SipComponent { var BYE_Request v_BYE_Request; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_BYE) -> value v_BYE_Request sender vc_sent_label { tc_wait.stop; vc_ignore_bye := true; f_setHeadersOnReceiptOfBYE(v_BYE_Request); // f_send200OK(); } } } // end f_awaitingBYE /** * @desc function awaiting BYE and sending 200OK response * @param p_BYE expected BYE */ function f_awaitingBYE_sendReply( in template(present) BYE_Request p_BYE := ? ) runs on SipComponent { var BYE_Request v_BYE_Request; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_BYE) -> value v_BYE_Request sender vc_sent_label { tc_wait.stop; vc_ignore_bye := true; f_setHeadersOnReceiptOfBYE(v_BYE_Request); f_send200OK(); } } } // end f_awaitingBYE_sendReply /** * @desc function awaiting BYE and sending 200OK response * @param p_BYE expected BYE */ function f_awaitingBYE_sendReply_PassOnTimeout( in template(present) BYE_Request p_BYE := ? ) runs on SipComponent { var BYE_Request v_BYE_Request; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_BYE) -> value v_BYE_Request sender vc_sent_label { tc_wait.stop; vc_ignore_bye := true; vc_boo_request := true; f_setHeadersOnReceiptOfBYE(v_BYE_Request); f_send200OK(); } [] tc_wait.timeout { vc_boo_request := false; } } } // end f_awaitingBYE_sendReply_PassOnTimeout /** * @desc function awaiting CANCEL * @param p_CANCEL expected CANCEL */ function f_awaitingCANCEL( in template(present) CANCEL_Request p_CANCEL := ? ) runs on SipComponent { var CANCEL_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_CANCEL) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); } } } // end f_awaitingCANCEL /** * @desc await MESSAGE request */ function f_awaitingMESSAGE( in template(present) MESSAGE_Request p_MSG := ? ) runs on SipComponent { var MESSAGE_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); } [] SIPP.receive(mw_MESSAGE_Request_Base) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); log("*** " &__SCOPE__& ": INFO: Received MESSAGE not as expected! ***"); setverdict(fail); } } } // end of f_awaitingMESSAGE /** * @desc await MESSAGE request reply with 200 OK */ function f_awaitingMESSAGE_sendReply( ) runs on SipComponent { var MESSAGE_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(mw_MESSAGE_Request_Base) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the MESSAGE f_send200OK(); } } } // end of f_awaitingMESSAGE_sendReply /** * @desc await MESSAGE request */ function f_awaitingMESSAGE_sendReply_PassOnTimeout( in template(present) MESSAGE_Request p_MSG := ? ) runs on SipComponent { var MESSAGE_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the MESSAGE // f_send200OK(); vc_boo_request := true; f_send200OK(); // setverdict (pass); } [] tc_wait.timeout { vc_boo_request := false; // setverdict (pass); } } } // end of f_awaitingMESSAGE_PassOnTimeout /** * @desc await NOTIFY request */ function f_awaitingNOTIFY( in template(present) NOTIFY_Request p_MSG := ? ) runs on SipComponent { var NOTIFY_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_getRouteMapIntoRecordRoute(v_MSG); f_setHeadersOnReceiptOfRequest(v_MSG); } } } // end of f_awaitingNOTIFY /** * @desc await NOTIFY request reply with 200 OK */ function f_awaitingNOTIFY_sendReply( in template(present) NOTIFY_Request p_MSG := ? ) runs on SipComponent { var NOTIFY_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_getRouteMapIntoRecordRoute(v_MSG); f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the NOTIFY f_send200OK(); } } } // end of f_awaitingNOTIFY_sendReply function f_awaitingNOTIFY_sendReply_postamble( in template(present) NOTIFY_Request p_MSG := ? ) runs on SipComponent { var NOTIFY_Request v_MSG; tc_wait.start(5.0); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_getRouteMapIntoRecordRoute(v_MSG); f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the NOTIFY f_send200OK(); } [] tc_wait.timeout { // do nothing as receiving the Notify in de-registration is not part of the test body } } } // end of f_awaitingNOTIFY_sendReply_postamble /** * @desc await PRACK request reply with 200 OK */ function f_awaitingPRACK_sendReply( in template(present) PRACK_Request p_MSG := ? ) runs on SipComponent { var PRACK_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the PRACK if (isvalue(vc_request.messageBody) and ischosen(vc_request.messageBody.sdpMessageBody)) { f_sendResponse(m_Response_mbody(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, omit, f_recordroute(), m_MBody_SDP(vc_sdp_local))); } else { f_sendResponse(m_Response_ext(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, omit, f_recordroute())); } } } } // end of f_awaitingPRACK_sendReply function f_awaitingPRACK( in template(present) PRACK_Request p_MSG := ? ) runs on SipComponent { var PRACK_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); } } } // end of f_awaitingPRACK /** * @desc await PUBLISH request reply with 200 OK */ function f_awaitingPUBLISH_sendReply( in template(present) PUBLISH_Request p_MSG := ? ) runs on SipComponent { var PUBLISH_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the PUBLISH f_send200OK(); } } } // end of f_awaitingPUBLISH_sendReply /** * @desc await UPDATE request */ function f_awaitingUPDATE( in template(present) UPDATE_Request p_MSG := ? ) runs on SipComponent { var UPDATE_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); } } } // end of f_awaitingUPDATE /** * @desc await UPDATE request reply with 200 OK */ function f_awaitingUPDATE_sendReply( in template(present) UPDATE_Request p_MSG := ? ) runs on SipComponent { var UPDATE_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the UPDATE if (isvalue(vc_request.messageBody) and ischosen(vc_request.messageBody.sdpMessageBody)) { f_sendResponse(m_Response_mbody(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, omit, f_recordroute(), m_MBody_SDP(vc_sdp_local))); } else { f_sendResponse(m_Response_ext(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via, omit, f_recordroute())); } } } } // end of f_awaitingUPDATE_sendReply /** * @desc await REFER request */ function f_awaitingREFER( in template(present) REFER_Request p_MSG := ? ) runs on SipComponent { var REFER_Request v_MSG; tc_wait.start(PX_SIP_TWAIT); alt { [] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { tc_wait.stop; f_setHeadersOnReceiptOfREFER(v_MSG); } } } // end of f_awaitingUPDATE } // end AwaitingMessage group SendMessage { /** * @desc send ACK message, update the route and recordRoute header fields depending on boolean flags * @param p_request template of the message to be sent */ function f_SendACK( template(value) ACK_Request p_request ) runs on SipComponent { // p_request.msgHeader.route := f_route(); // update the route header field depending on vc_boo_route // n/a p_request.msgHeader.recordRoute := f_recordroute(); // update the route header field depending on vc_boo_route SIPP.send(p_request) to vc_sent_label; } /** * @desc send BYE message, update the route and recordRoute header fields depending on boolean flags * @param p_request template of the message to be sent */ function f_SendBYE( template(value) BYE_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send CANCEL message * @param p_request template of the message to be sent */ function f_SendCANCEL( template(value) CANCEL_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send INFO message * @param p_request template of the message to be sent */ function f_SendINFO( template(value) INFO_Request p_request ) runs on SipComponent { f_setHeadersGeneral(vc_cSeq, "INFO"); // cseq, contact, branch, via SIPP.send(p_request) to vc_sent_label; } /** * @desc send INVITE message * @param p_request template of the message to be sent */ function f_SendINVITE( template(value) INVITE_Request p_request ) runs on SipComponent { vc_requestFor407 := valueof(p_request); SIPP.send(p_request) to vc_sent_label; vc_request := vc_requestFor407; if (PX_SIP_INVITE_AUTHENTICATION_ENABLED) { a_altstep_401or407(); } } /** * @desc send PRACK message * @param p_request template of the message to be sent */ function f_SendPRACK( ) runs on SipComponent { var integer responseNum := 1; var PRACK_Request prackReq; if (isvalue(vc_response.msgHeader.rSeq) and isvalue(vc_response.msgHeader.rSeq.responseNum)){ responseNum := vc_response.msgHeader.rSeq.responseNum; } vc_rAck := valueof(m_RAck(vc_response.msgHeader.rSeq.responseNum, vc_cSeq.seqNumber, vc_cSeq.method)); f_setHeadersGeneral(vc_cSeq, "PRACK"); // cseq, contact, branch, via prackReq := valueof(m_PRACK_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via, vc_rAck)); if (isvalue(vc_response.msgHeader.recordRoute)){ prackReq.msgHeader.route := valueof(f_route()); } SIPP.send(prackReq) to vc_sent_label; } /** * @desc send PUBLISH message * @param p_request template of the message to be sent */ function f_SendPUBLISH( template(value) PUBLISH_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send REGISTER message * @param p_request template of the message to be sent */ function f_SendREGISTER( template(value) REGISTER_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send SUBSCRIBE message * @param p_request template of the message to be sent */ function f_SendSUBSCRIBE( template(value) SUBSCRIBE_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send UPDATE message * @param p_request template of the message to be sent */ function f_SendUPDATE( template(value) UPDATE_Request p_request ) runs on SipComponent { f_setHeadersGeneral(vc_cSeq, "UPDATE"); // cseq, contact, branch, via p_request.msgHeader.cSeq := vc_cSeq; p_request.msgHeader.contact := vc_contact; p_request.msgHeader.via := vc_via; vc_requestFor407 := valueof(p_request); SIPP.send(p_request) to vc_sent_label; if (PX_SIP_INVITE_AUTHENTICATION_ENABLED) { a_altstep_401or407(); } } /** * @desc function send MESSAGE message * @param p_request template of the message to be sent */ function f_SendMESSAGE( template(value) MESSAGE_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc function send NOTIFY message * @param p_request template of the notify to be sent */ function f_SendNOTIFY( template(value) NOTIFY_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send REFER message * @param p_request template of the message to be sent */ function f_SendREFER( template(value) REFER_Request p_request ) runs on SipComponent { SIPP.send(p_request) to vc_sent_label; } /** * @desc send 200 OK */ function f_send200OK( ) runs on SipComponent { f_sendResponse(m_Response_Base(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via)); } /** * @desc send response * @param p_request template of the message to be sent */ function f_sendResponse( template(value) Response p_response ) runs on SipComponent { p_response.msgHeader.route := f_route(); // update the route header field depending on vc_boo_route p_response.msgHeader.recordRoute := f_recordroute(); // update the route header field depending on vc_boo_route SIPP.send(p_response) to vc_sent_label; } } // end SendMessage group GlobalSteps { /** * @desc component initialization * @param p_cSeq_s cSeq value to be assigned to the component variable */ function f_init_component( inout CSeq p_cSeq_s ) runs on SipComponent { // Variables vc_cSeq := p_cSeq_s; // Defaults vc_def_catchSyncStop := activate(a_Sip_catchSyncStop()); vc_default := activate(a_clearRegistration()); } /** * @desc component termination */ function f_terminate_component( ) runs on SipComponent { log("*** " &__SCOPE__& ": INFO: component terminated - forced! ***"); deactivate; stop; } /** * @desc component termination */ function f_componentStop( ) runs on SipComponent { syncPort.send(m_syncClientStop); SIPP.clear; stop; } /** * @desc function waits for particular time that allows the SUT to return to idle state */ function f_awaitSUTidle( ) runs on SipComponent { vc_ignore4xx := true; // allow 4xx in default tc_noAct.start; alt { [] tc_noAct.timeout { } } } /** * @desc function waits for particular time before next expected message */ function f_wait( float p_time ) runs on SipComponent { tc_noAct.start(p_time); alt { [] tc_noAct.timeout { } } } /** * @desc function cause termination of a PTC * @param p_syncPoint dummy parameter (copied from the common lib) */ function f_check2Null( in charstring p_syncPoint ) runs on SipComponent { // != pass does not work, because in case of "none" execution shall continue if (getverdict == inconc or getverdict == fail) { log("*** f_check2Null: INFO: Verdict evaluated to fail or inconc. Stopping test execution now ***"); f_selfOrClientSyncAndVerdict(p_syncPoint, e_error); } // end if } /* * * @desc original copied from older LibCommon_VerdictControl */ function f_getVerdict( ) return FncRetCode { var FncRetCode v_ret := e_error; if (getverdict == pass or getverdict == none) { v_ret := e_success; } return v_ret; } } // end group GlobalSteps group Registration { /** * @desc registration and authentication with MD5 * @param p_cSeq_s cseq parameter * @param p_register register template * @param p_auth flag indicating if authentication is needed * @param p_emergency Set to true in case of emergency call */ function f_Registration( inout CSeq p_cSeq_s, out template(value) REGISTER_Request p_register, in boolean p_auth, in boolean p_emergency := false ) runs on SipComponent { if (PX_SIP_REGISTRATION) { f_setHeaders_REGISTER(p_cSeq_s, p_emergency); p_register := m_REGISTER_Request_Base(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via_REG, vc_contact, vc_authorization); f_SendREGISTER(p_register); // LibSip // awaiting of 401 and sending 2nd REGISTER and awaiting 200 OK REGISTER if (p_auth) { // receiving 401 Unauthorized response. // and Re-send REGISTER request with Authorization header tc_resp.start; alt { [] SIPP.receive(mw_Response_Base(c_statusLine401, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // set headers via, cseq and authorization f_setHeaders_2ndREGISTER(p_cSeq_s); p_register := m_REGISTER_Request_Base(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via_REG, vc_contact, vc_authorization); // Re-send protected REGISTER f_SendREGISTER(p_register); // LibSip // awaiting 200 OK REGISTER f_awaitingOkResponse(p_cSeq_s); f_getServiceRouteMapIntoRouteInRegistration(vc_response); } [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); f_getServiceRouteMapIntoRouteInRegistration(vc_response); log("*** " &__SCOPE__& ": INFO: Authorization was not requested as expected ***"); } } } else { f_awaitingOkResponse(p_cSeq_s); f_getServiceRouteMapIntoRouteInRegistration(vc_response); } } } // end function f_Registration /** * @desc registration and authentication with MD5 * @param p_cSeq_s cseq parameter * @param p_register register template * @param p_auth flag indicating if authentication is needed */ function f_Registration_withTemplate( inout CSeq p_cSeq_s, inout template(value) REGISTER_Request p_register, in boolean p_auth ) runs on SipComponent { if (PX_SIP_REGISTRATION) { if(not isbound(p_register)){ f_setHeaders_REGISTER(p_cSeq_s); p_register := m_REGISTER_Request_Base(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via_REG, vc_contact, vc_authorization); } f_SendREGISTER(p_register); // LibSip // awaiting of 401 and sending 2nd REGISTER and awaiting 200 OK REGISTER if (p_auth) { // receiving 401 Unauthorized response. // and Re-send REGISTER request with Authorization header tc_resp.start; alt { [] SIPP.receive(mw_Response_Base(c_statusLine401, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // set headers via, cseq and authorization f_setHeaders_2ndREGISTER(p_cSeq_s); // p_register := m_REGISTER_Request_Base(vc_requestUri, vc_callId, p_cSeq_s, vc_from, vc_to, vc_via_REG, vc_contact, // vc_authorization); // Re-send protected REGISTER p_register.requestLine.requestUri := vc_requestUri; p_register.msgHeader.cSeq := vc_cSeq; p_register.msgHeader.via := vc_via_REG; p_register.msgHeader.authorization := vc_authorization; f_SendREGISTER(p_register); // LibSip // awaiting 200 OK REGISTER f_awaitingOkResponse(p_cSeq_s); f_getServiceRouteMapIntoRouteInRegistration(vc_response); } [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, p_cSeq_s)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); f_getServiceRouteMapIntoRouteInRegistration(vc_response); log("*** " &__SCOPE__& ": INFO: Authorization was not requested as expected ***"); } } } else { f_awaitingOkResponse(p_cSeq_s); f_getServiceRouteMapIntoRouteInRegistration(vc_response); } } } // end function f_Registration_withTemplate /** * @desc remove registration * @param p_cSeq_s cseq parameter */ function f_RemoveRegistration( inout CSeq p_cSeq ) runs on SipComponent { var template(value) REGISTER_Request v_request; var boolean v_receivedNotify := false; // if (vc_DeregDone) { f_componentStop(); } else { vc_DeregDone := true; } if (PX_SIP_REGISTRATION) { f_setHeaders_deREGISTER(p_cSeq); v_request := m_REGISTER_Request_expires(vc_requestUri, vc_callIdReg, p_cSeq, vc_from, vc_to, vc_via_REG, vc_contact, vc_authorization, "0"); f_SendREGISTER(v_request); if (PX_SIP_REGISTER_AUTHENTICATION_ENABLED) { // receiving 401 Unauthorized response. // and Re-send REGISTER request with Authorization header tc_resp.start; alt { [] SIPP.receive(mw_Response_Base(c_statusLine401, vc_callIdReg, p_cSeq)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // set headers via, cseq and authorization f_setHeaders_2ndREGISTER(p_cSeq); v_request := m_REGISTER_Request_expires(vc_requestUri, vc_callIdReg, p_cSeq, vc_from, vc_to, vc_via_REG, vc_contact, vc_authorization, "0"); // v_request.msgHeader.route := f_route(); // Re-send protected REGISTER f_SendREGISTER(v_request); // LibSip // awaiting 200 OK REGISTER f_awaitingResponse(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq)); } [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq)) -> value vc_response { tc_resp.stop; f_setHeadersOnReceiptOfResponse(vc_response); // log ("Authorization was not requested as expected"); } [] a_awaitNotify(mw_NOTIFY_Request_Base(vc_callIdSub), v_receivedNotify) { } } } else { tc_resp.start; alt { [] a_awaitingResponse(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq)) { } [] a_awaitNotify(mw_NOTIFY_Request_Base(vc_callIdSub), v_receivedNotify) { } } } // await NOTIFY and send reply 200 OK if (vc_subscribed and v_receivedNotify == false) { f_awaitingNOTIFY_sendReply_postamble(mw_NOTIFY_Request_Base(vc_callIdReg)); } } } // end f_RemoveRegistration /** * @desc remove registration without authorization * @param p_cSeq_s cseq parameter */ function f_RemoveRegistration_wo_authorization( inout CSeq p_cSeq ) runs on SipComponent { if (PX_SIP_REGISTRATION) { f_setHeaders_deREGISTER(p_cSeq); f_SendREGISTER(m_REGISTER_Request_expires(vc_requestUri, vc_callIdReg, p_cSeq, vc_from, vc_to, vc_via, vc_contact, vc_authorization, "0")); f_awaitingResponse(mw_Response_Base(c_statusLine200, vc_callIdReg, p_cSeq)); } } // end f_RemoveRegistration_wo_authorization } // end group Registration group Subscription { /** * @desc UE send subscrbe, await on 200 OK, await notify and send 200 OK * @param p_cSeq_s cseq parameter * @param p_subscribe subscribe template */ function f_Subscription( inout CSeq p_cSeq_s, template(value) SUBSCRIBE_Request p_subscribe ) runs on SipComponent { // send SUBSCRIBE f_SendSUBSCRIBE(p_subscribe); // awaiting 200 OK SUBSCRIBE // await NOTIFY and send reply 200 OK f_awaitingOkResponseAndNOTIFY_sendReply(p_cSeq_s, mw_NOTIFY_Request_Base(vc_callId)); } // end function f_Subscription /** * @desc UE send subscrbe, await on 200 OK, await notify and send 200 OK * @param p_cSeq_s cseq parameter * @param p_subscribe subscribe template * @param p_notify notify template */ function f_SubscriptionWithNotification( inout CSeq p_cSeq_s, template(value) SUBSCRIBE_Request p_subscribe, template(present) NOTIFY_Request p_notify := ? ) runs on SipComponent { f_setHeaders_SUBSCRIBE(p_cSeq_s); // send SUBSCRIBE f_SendSUBSCRIBE(p_subscribe); // awaiting 200 OK SUBSCRIBE // await NOTIFY and send reply 200 OK f_awaitingOkResponseAndNOTIFY_sendReply(p_cSeq_s, p_notify); } // end function f_SubscriptionWithNotification /** * @desc UE await subscrbe, send on 200 OK; possibility to handle also other SUBSCRIBE methods where event is different than reg * @param p_cSeq_s cseq parameter * @param p_subscribe subscribe template */ function f_awaitingSubscription( template(present) SUBSCRIBE_Request p_subscribe := ? ) runs on SipComponent { var SUBSCRIBE_Request v_request; tc_wait.start(2.0); // awaiting of all SUBSCRIBES alt { [] SIPP.receive(p_subscribe) -> value v_request sender vc_sent_label { f_setHeadersOnReceiptOfSUBSCRIBE(v_request); f_send200OK(); repeat; } [] SIPP.receive(mw_SUBSCRIBE_Request_Base) -> value v_request sender vc_sent_label { f_setHeadersOnReceiptOfSUBSCRIBE(v_request); f_send200OK(); repeat; } [] tc_wait.timeout { setverdict(pass); } } } // end function f_awaitingSubscription } // end group Subscription group Preambles { /** * @desc Set variables and default initialization for user profile * @param p_userprofile user profile of call * @param p_cSeq_s cseq parameter */ function f_SIP_preamble_woREG( inout CSeq p_cSeq_s ) runs on SipComponent { // varables and altsteps f_init_component(p_cSeq_s); // Preamble //NOTE STF471: removed f_init_userprofile(p_userprofile); // assignment of PIXIT values to component variable vc_sdp_local := valueof(m_SDP_bandwidth(m_media_dynPT(PX_SIP_SDP_DYN, PX_SIP_SDP_ENCODING, PX_SIP_SDP_CLOCKRATE, omit), vc_userprofile)); } /** * @desc Set variables and default initialization for user profile and handle registration and authentication with MD5 * @param p_userprofile user profile of call * @param p_cSeq_s cseq parameter * @param p_register register template */ function f_SIP_preamble_withREG( inout CSeq p_cSeq_s, template(value) REGISTER_Request p_register ) runs on SipComponent { // preamble f_SIP_preamble_woREG(p_cSeq_s); // Registration, Awaiting f_Registration(p_cSeq_s, p_register, PX_SIP_REGISTER_AUTHENTICATION_ENABLED); } } // end group Preambles group Postambles { /** * @desc function send BYE and awaits reponse * @param p_CallId parameter for outgoing BYE * @param p_cSeq parameter for outgoing BYE * @param p_from parameter for outgoing BYE * @param p_to parameter for outgoing BYE * @param p_reqHostPort parameter for outgoing BYE * @param p_byeCause parameter for Release cause to be used * in BYE and in Failure messages, former PX_SIP_BYE_CAUSE */ function f_terminateCall( SipUrl p_requestUri, CallId p_CallId, inout CSeq p_cSeq, From p_from, template(value) To p_to, integer p_byeCause ) runs on SipComponent { // Sending of a BYE request to release the call and expect a final response f_SendBYE(m_BYE_Request_cause(p_requestUri, p_CallId, p_cSeq, p_from, p_to, vc_via, p_byeCause)); tc_resp.start; alt { [] SIPP.receive(mw_Response_Base(mw_statusLine1xx, p_CallId, p_cSeq)) { repeat; } [] SIPP.receive(mw_Response_Base(mw_statusLineFinal, p_CallId, p_cSeq)) { tc_resp.stop; } } } // end function f_terminateCall function f_cancelCall( template(value) CANCEL_Request p_request ) runs on SipComponent { // This function is called to bring back the IUT in idle condition // in case of errors or unexpected behaviour. // Sending of a CANCEL request with the same Cseq f_setHeadersCANCEL(vc_cSeq); f_SendCANCEL(p_request); tc_resp.start; alt { [] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, vc_cSeq)) { tc_resp.stop; } } } function f_cancelCall_await487( template(value) CANCEL_Request p_request ) runs on SipComponent { // This function is called to bring back the IUT in idle condition // in case of errors or unexpected behaviour. // Sending of a CANCEL request with the same Cseq f_cancelCall(p_request); // set method on INVITE vc_cSeq.method := "INVITE"; // await on 487 response and send ACK f_awaitingResponse(mw_Response_Base(c_statusLine487, vc_callId, vc_cSeq)); f_SendACK(m_ACK_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)); } function f_awaitCancelCall_send487( template(present) CANCEL_Request p_request := ? ) runs on SipComponent { f_awaitingCANCEL(p_request); f_sendResponse(m_Response_Base(c_statusLine200, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via)); // set method on INVITE vc_cSeq.method := "INVITE"; // send 487 response and await ACK f_sendResponse(m_Response_Base(c_statusLine487, vc_callId, vc_cSeq, vc_caller_From, vc_caller_To, vc_via)); // await ACK f_awaitingACK(mw_ACK_Request_Base(vc_callId)); } altstep a_receiveCANCELorNothing( in template(present) CANCEL_Request p_CANCEL := ? ) runs on SipComponent { var CANCEL_Request v_MSG; [] SIPP.receive(p_CANCEL) -> value v_MSG sender vc_sent_label { f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the CANCEL f_send200OK(); } } altstep a_awaitNotify( in template(present) NOTIFY_Request p_MSG := ?, inout boolean p_receivedNotify ) runs on SipComponent { var NOTIFY_Request v_MSG; [vc_subscribed] SIPP.receive(p_MSG) -> value v_MSG sender vc_sent_label { p_receivedNotify := true; f_getRouteMapIntoRecordRoute(v_MSG); f_setHeadersOnReceiptOfRequest(v_MSG); // Answer to the NOTIFY f_send200OK(); repeat; } } } // end group Postambles group SipChecks { /** * @desc check the presence of conversation at SIP side * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_Conversation( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if conversation at SIP port"; if (p_checkConversation) { opPort .call( s_SIP_conversation: { v_question, - } ) { [] opPort .getreply( s_SIP_conversation: { -, true } ) { } [] opPort .getreply( s_SIP_conversation: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_uPlane, f_getVerdict()); // Note: implemented in test bodies return; } // end of f_check_Conversation /** * @desc check the presence of conversation at SIP side * @param p_checkRinging boolean to perform check if ringing check is implemented. * former PX_SIP_CHECK_RINGING */ function f_check_Ringing( boolean p_checkRinging := false ) runs on SipComponent { var charstring v_question := "confirm if ringing at SIP port"; if (p_checkRinging) { opPort .call( s_SIP_ringing: { v_question, - } ) { [] opPort .getreply( s_SIP_ringing: { -, true } ) { } [] opPort .getreply( s_SIP_ringing: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_Ringing, f_getVerdict()); return; } // end of f_check_Ringing /** * @desc check the announcement at SIP side (UE A) * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_AnnouncementUE_A( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if announcement at UE A"; if (p_checkConversation) { opPort .call( s_SIP_announcementA: { v_question, - } ) { [] opPort .getreply( s_SIP_announcementA: { -, true } ) { } [] opPort .getreply( s_SIP_announcementA: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_annoucA, f_getVerdict()); return; } // end of f_check_AnnouncementUE_A /** * @desc check the announcement at SIP side (UE B) * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_AnnouncementUE_B( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if announcement at UE B"; if (p_checkConversation) { opPort .call( s_SIP_announcementB: { v_question, - } ) { [] opPort .getreply( s_SIP_announcementB: { -, true } ) { } [] opPort .getreply( s_SIP_announcementB: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_annoucB, f_getVerdict()); return; } // end of f_check_AnnouncementUE_B /** * @desc check the announcement at SIP side * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_Announcement( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if announcement at SIP side"; if (p_checkConversation) { opPort .call( s_SIP_announcement: { v_question, - } ) { [] opPort .getreply( s_SIP_announcement: { -, true } ) { } [] opPort .getreply( s_SIP_announcement: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_annouc, f_getVerdict()); return; } // end of f_check_Announcement /** * @desc check the Voice message at SIP side * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_VoiceMessage( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if voice message at SIP side"; if (p_checkConversation) { opPort .call( s_SIP_voiceMessage: { v_question, - } ) { [] opPort .getreply( s_SIP_voiceMessage: { -, true } ) { } [] opPort .getreply( s_SIP_voiceMessage: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_voicem, f_getVerdict()); return; } // end of f_check_Announcement /** * @desc check the stop of media stream * @param p_checkConversation boolean to perform check if conversation check is implemented. * former PX_SIP_CHECK_CONVERSATION */ function f_check_MediaStopped( boolean p_checkConversation := false ) runs on SipComponent { var charstring v_question := "confirm if media stream stopped"; if (p_checkConversation) { opPort .call( s_SIP_mediastopped: { v_question, - } ) { [] opPort .getreply( s_SIP_mediastopped: { -, true } ) { } [] opPort .getreply( s_SIP_mediastopped: { -, false } ) { all timer.stop; setverdict(fail); syncPort.send(m_syncClientStop); stop; } }; } f_selfOrClientSyncAndVerdict(c_uPlaneStop, f_getVerdict()); return; } // end of f_check_MediaStopped } group DefaultsTestStep { /** * @desc This default handles receiving of the sync server STOP message and calls the RT HUT postamble. (copy from common lib) */ altstep a_Sip_catchSyncStop( ) runs on SipComponent { [] syncPort.receive(m_syncServerStop) { tc_sync.stop; log("*** a_Sip_catchSyncStop: INFO: Test component received STOP signal from MTC - going to IDLE state *** "); syncPort.send(m_syncClientStop); // in case if deregistration was not done // f_RemoveRegistration(vc_cSeq); f_terminate_component(); log("*** a_Sip_catchSyncStop: INFO: TEST COMPONENT NOW STOPPING ITSELF! *** "); setverdict(inconc); stop; } } /** * @desc main default altstep to handle unexpected messages and timeout * @verdict fail for all unexpected branches */ altstep a_clearRegistration( ) runs on SipComponent { var Response v_response; var Request v_request; var INFO_Request v_info_request; var NOTIFY_Request v_notify_request; var SUBSCRIBE_Request v_subscribe_request; var BYE_Request v_bye_request; var CANCEL_Request v_cancel_request; var REGISTER_Request v_register_request; var CSeq v_cSeq; [] any timer.timeout { setverdict(fail); all timer.stop; // f_SendCANCEL(m_CANCEL_Request(vc_callId, vc_cSeq, vc_from, vc_cancel_To, vc_reqHostPort, vc_via )); // difference between registration // state or transaction state vc_callId := vc_callIdReg; f_RemoveRegistration(vc_cSeq); } // allow repeated INVITEs [vc_ignore_invite] SIPP.receive(mw_INVITE_Request_Base) { repeat; } // allow repeated BYEs after ack of the first BYE [vc_ignore_bye] SIPP.receive(mw_BYE_Request_Base(?)) { repeat; } [] SIPP.receive(mw_ACK_Request_Base(?)) { repeat; } // allow 100 replies [] SIPP.receive(mw_Response_Base(c_statusLine100, ?, ?)) { repeat; } // ignore 181 if flag is set (following TS 183004 4.5.2.1) [vc_ignore181] SIPP.receive(mw_Response_Base(c_statusLine181, vc_callId, vc_cSeq)) -> value v_response sender vc_sent_label { v_cSeq := valueof(v_response.msgHeader.cSeq); f_setHeadersOnReceiptOfResponse(v_response); // CSeq is mandatory repeat; } // according to SIP chap.8.1.3.2 [] SIPP.receive(mw_Response_Base(c_statusLine183, vc_callId, vc_cSeq)) { repeat; } // ignore 484 if flag is set [vc_ignore484] SIPP.receive(mw_Response_Base(c_statusLine484, vc_callId, vc_cSeq)) { repeat; } [vc_ignore4xx] SIPP.receive(mw_Response_Base(mw_statusLine4xx, vc_callId, ?)) -> value v_response sender vc_sent_label { v_cSeq := valueof(v_response.msgHeader.cSeq); f_setHeadersOnReceiptOfResponse(v_response); // CSeq is mandatory f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route)); repeat; } [vc_ignore200OKinv] SIPP.receive(mw_Response_Base(c_statusLine200, vc_callId, ?)) { repeat; } [] SIPP.receive(mw_INFO_Request_Base(vc_callId)) -> value v_info_request sender vc_sent_label { f_setHeadersOnReceiptOfRequest(v_info_request); f_send200OK(); repeat; } // awaiting of Notify [] SIPP.receive(mw_NOTIFY_Request_Base(vc_callId)) -> value v_notify_request sender vc_sent_label { f_setHeadersOnReceiptOfRequest(v_notify_request); f_send200OK(); repeat; } // awaiting of subscribe from UE [vc_ignore_subscribe] SIPP.receive(mw_SUBSCRIBE_Request_Base) -> value v_subscribe_request sender vc_sent_label { f_setHeadersOnReceiptOfSUBSCRIBE(v_subscribe_request); f_send200OK(); repeat; } // awaiting of subscribe on proxy [] SIPP.receive(mw_SUBSCRIBE_Request_Base) -> value v_subscribe_request sender vc_sent_label { f_setHeadersOnReceiptOfRequest(v_subscribe_request); f_sendResponse(m_Response_Contact(c_statusLine200, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact)); // f_setHeadersGeneral(vc_cSeq, "NOTIFY"); // cseq, contact, branch, via // f_SendNOTIFY(m_NOTIFY_Request_contact(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via, vc_contact)); f_SendNOTIFY(m_NOTIFY_Request_contact(v_subscribe_request.msgHeader.contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec, vc_callId, vc_cSeq, vc_callee_From, vc_callee_To, vc_via, vc_contact)); f_awaitingOkResponse(vc_cSeq); repeat; } // unexpected BYE is acknowledged to avoid retransmissions [] SIPP.receive(mw_BYE_Request_Base(?)) -> value v_bye_request sender vc_sent_label { setverdict(fail); f_setHeadersOnReceiptOfRequest(v_bye_request); f_send200OK(); f_RemoveRegistration(vc_cSeq); } // unexpected CANCEL is acknowledged to avoid retransmissions [] SIPP.receive(mw_CANCEL_Request_Base(?)) -> value v_cancel_request sender vc_sent_label { setverdict(fail); f_setHeadersOnReceiptOfRequest(v_cancel_request); // Answer to the CANCEL f_send200OK(); f_RemoveRegistration(vc_cSeq); } // catch 4xx response [] SIPP.receive(mw_Response_Base(mw_statusLine4xx, vc_callId, ?)) -> value v_response sender vc_sent_label { setverdict(fail); if (v_response.msgHeader.cSeq.method == "INVITE") { v_cSeq := valueof(v_response.msgHeader.cSeq); f_setHeadersOnReceiptOfResponse(v_response); // CSeq is mandatory LibSip_Steps.f_setHeadersACK(); f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route)); } f_RemoveRegistration(vc_cSeq); } // catch 5xx response [] SIPP.receive(mw_Response_Base(mw_statusLine5xx, vc_callId, ?)) -> value v_response sender vc_sent_label { setverdict(fail); if (v_response.msgHeader.cSeq.method == "INVITE") { v_cSeq := valueof(v_response.msgHeader.cSeq); f_setHeadersOnReceiptOfResponse(v_response); // CSeq is mandatory LibSip_Steps.f_setHeadersACK(); f_SendACK(m_ACK_Request_route(vc_requestUri, vc_callId, v_response.msgHeader.cSeq, vc_from, vc_to, vc_via, vc_route)); } f_RemoveRegistration(vc_cSeq); } // catch invalid REGISTER [] SIPP.receive(mw_REGISTER_Request_Base) -> value v_register_request sender vc_sent_label { setverdict(fail); f_componentStop(); } // any [] SIPP.receive { setverdict(fail); all timer.stop; // f_setHeadersCANCEL(vc_cSeq); // f_SendCANCEL(m_CANCEL_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_cancel_To, vc_via )); // difference between // registration state or transaction state f_RemoveRegistration(vc_cSeq); } } /** * @desc altstep handle authentication for INVITE message */ altstep a_altstep_401or407( ) runs on SipComponent { var CommaParam_List v_challenge; var Credentials v_Credentials; var Response v_Response; var Request v_Request := vc_requestFor407; [] any port.check(receive) { tc_resp.start; alt { [] SIPP.receive(mw_Response_Base((c_statusLine401, c_statusLine407), vc_callId, vc_cSeq)) -> value v_Response { tc_resp.stop; // get tag from To header if available vc_to := v_Response.msgHeader.toField; if (vc_cSeq.method == "INVITE") { // send ACK f_SendACK(m_ACK_Request_Base(vc_requestUri, vc_callId, vc_cSeq, vc_from, vc_to, vc_via)); } // resent the INVITE message with Proxyauthorization header include // Extract challenge and calculate credentials for a response. if ( ischosen( v_Response.msgHeader.proxyAuthenticate.challenge .otherChallenge // instead of digestCln (changed by axr to comply to alcatel) ) ) { v_challenge := v_Response.msgHeader.proxyAuthenticate.challenge.otherChallenge.authParams; v_Credentials := f_calculatecCredentials(vc_userprofile, vc_requestFor407.msgHeader.cSeq.method, v_challenge); } else { log("*** " &__SCOPE__& ": INFO: No scheme in Proxy Authenticate header!!! ***"); setverdict(inconc); stop; } vc_branch := c_branchCookie & f_getRndTag(); vc_via := { fieldName := VIA_E, viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))} }; v_Request.msgHeader.via := vc_via; // Increment CSeq sequence number of and add the credentials // to the original saved INVITE message. vc_cSeq.method := vc_requestFor407.msgHeader.cSeq.method; vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1; v_Request.msgHeader.cSeq.seqNumber := vc_cSeq.seqNumber; v_Request.msgHeader.proxyAuthorization.fieldName := PROXY_AUTHORIZATION_E; v_Request.msgHeader.proxyAuthorization.credentials := {v_Credentials}; // Re-send the saved INVITE with Authorization header // included. SIPP.send(v_Request) to vc_sent_label; } } } } } // end of group DefaultsTestStep } // end module LibSip_Steps