LibSip_Steps.ttcn 203 KB
Newer Older
/**
 * @author      STF 346, STF366, STF368, STF369, STF450, STF471
Yann Garcia's avatar
Yann Garcia committed
 * @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
Yann Garcia's avatar
Yann Garcia committed
            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.
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "username",
                paramValue := { quotedString := v_username }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "realm",
                paramValue := { quotedString := v_realm }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "uri",
                paramValue := { quotedString := v_uri }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nonce",
                paramValue := { quotedString := "" }
            }); // already enclosed to " characters
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "response",
                paramValue := { quotedString := "" }
            }); // already enclosed to " characters

            if (p_algorithm) {
Yann Garcia's avatar
Yann Garcia committed
                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.
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "username",
                paramValue := { quotedString := v_username }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "realm",
                paramValue := { quotedString := v_realm }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nonce",
                paramValue := { quotedString := v_nonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "uri",
                paramValue := { quotedString := v_uri }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "response",
                paramValue := { quotedString := v_response }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "algorithm",
                paramValue := { tokenOrHost := "md5" }
            }); // algorithm is not enclosed to " characters
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "cnonce",
                paramValue := { quotedString := v_cnonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "qop",
                paramValue := { tokenOrHost := v_qop }
            }); // qop
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nc",
                paramValue := { tokenOrHost := cl_nonceCount }
            }); // nonceCount
            if (v_opaque != "") {
Yann Garcia's avatar
Yann Garcia committed
                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);

Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "username",
                paramValue := { quotedString := v_username }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "realm",
                paramValue := { quotedString := v_realm }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nonce",
                paramValue := { quotedString := v_nonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "uri",
                paramValue := { quotedString := v_uri }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "algorithm",
                paramValue := { tokenOrHost := "md5" }
            }); // algorithm is not enclosed to " characters
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "cnonce",
                paramValue := { quotedString := v_cnonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "qop",
                paramValue := { tokenOrHost := v_qop }
            }); // qop
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nc",
                paramValue := { tokenOrHost := cl_nonceCount }
            }); // nonceCount
            if (v_opaque == "") {
Yann Garcia's avatar
Yann Garcia committed
                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.
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "username",
                paramValue := { quotedString := "DifferentToPrivateUser" }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "realm",
                paramValue := { quotedString := v_realm }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nonce",
                paramValue := { quotedString := v_nonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "uri",
                paramValue := { quotedString := v_uri }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "response",
                paramValue := { quotedString := v_response }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "algorithm",
                paramValue := { tokenOrHost := "md5" }
            }); // algorithm is not enclosed to " characters
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "cnonce",
                paramValue := { quotedString := v_cnonce }
            });
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "qop",
                paramValue := { tokenOrHost := v_qop }
            }); // qop
Yann Garcia's avatar
Yann Garcia committed
            v_digestResponse := f_addParameter(v_digestResponse, {
                id := "nc",
                paramValue := { tokenOrHost := cl_nonceCount }
            });
            if (v_opaque != "") {
Yann Garcia's avatar
Yann Garcia committed
                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)) {
Yann Garcia's avatar
Yann Garcia committed
                v_size_recordRoute := lengthof(valueof(p_recordRoute).routeBody);
            }
            for (i := 1; i < v_size_recordRoute + 1; i := i + 1) {
Yann Garcia's avatar
Yann Garcia committed
                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  {
Yann Garcia's avatar
Yann Garcia committed
            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. <sip:p.home.com>) 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(