Rev

Rev 614 | Details | Compare with Previous | Last modification | View Log | SVN | Bug Tracker

Rev Author Line No. Line
467 poglitsch 1
/*
584 garciay 2
 * @author      STF 346, STF366, STF368, STF369, STF450, STF471
3
 * @version     $Id: LibSip_Steps.ttcn 617 2014-07-07 12:31:12Z tepelmann $
4
 * @desc        This module provides the types used by the test component
9 rennoch 5
 *              for SIP-IMS tests.
534 rennoch 6
 *              This module is part of LibSipV2.
9 rennoch 7
 */
584 garciay 8
module LibSip_Steps {
9
    // LibCommon
10
    import from LibCommon_Sync all;
11
    import from LibCommon_VerdictControl all;
12
    // LibSip
13
    import from LibSip_SIPTypesAndValues all;
14
    import from LibSip_SDPTypes all;
15
    import from LibSip_Templates all;
16
    import from LibSip_Interface all;
17
    import from LibSip_PIXITS all;
18
    import from LibSip_XMLTypes all;
9 rennoch 19
 
584 garciay 20
    group externalfunctions {
9 rennoch 21
 
599 tepelmann 22
        // Return random charstring
600 nikolajev 23
        external function fx_rndStr(
24
        ) return charstring;
25
 
599 tepelmann 26
        // Return the equivalent string in lower case
600 nikolajev 27
        external function fx_putInLowercase(
607 nikolajev 28
            charstring p_string
600 nikolajev 29
        ) return charstring;
9 rennoch 30
 
600 nikolajev 31
        external function fx_getIpAddr(
607 nikolajev 32
            charstring p_host_name
600 nikolajev 33
        ) return charstring;
9 rennoch 34
 
584 garciay 35
        /**
36
         * @desc External function to generate a digest response.
37
         * @reference RFC 2617 HTTP Authentication: Basic and Digest Access Authentication, and RFC 1321 The MD5 Message-Digest Algorithm
599 tepelmann 38
         * @see RFC 2617, chapter 5 Sample implementation, for example usage, as the signature of calculateDigestResponse is according to the example given in the RFC.
584 garciay 39
         */
599 tepelmann 40
        external function fx_calculateDigestResponse(
607 nikolajev 41
            charstring p_nonce,
42
            charstring p_cnonce,
43
            charstring p_user,
44
            charstring p_realm,
45
            charstring p_passwd,
46
            charstring p_alg,
47
            charstring p_nonceCount,
48
            charstring p_method,
49
            charstring p_qop,
50
            charstring p_URI,
51
            charstring p_HEntity
599 tepelmann 52
        ) return charstring;
9 rennoch 53
 
584 garciay 54
    }
9 rennoch 55
 
584 garciay 56
    group ParameterOperations {
9 rennoch 57
 
584 garciay 58
        /**
599 tepelmann 59
         * @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)
584 garciay 60
         * @return random value with at least 32 bits of randomness
61
         */
600 nikolajev 62
        function f_getRndTag(
63
        ) return charstring  {
607 nikolajev 64
            var charstring v_tag_value;
599 tepelmann 65
            // tag_value is initialized with a random value with at least 32 bits of randomness
66
            // 4294967296 is a 32 bits integer
607 nikolajev 67
            v_tag_value := fx_rndStr() & fx_rndStr();
68
            return (v_tag_value);
584 garciay 69
        }
9 rennoch 70
 
584 garciay 71
        /**
72
         * @desc Function to prepare credentials for request that has an empty entity body such as a REGISTER message.
73
         * @param p_userprofile to get important parameters
74
         * @param p_algorithm Algorthm to be used. Default: omit
75
         * @return Credentials field
76
         */
599 tepelmann 77
        function f_calculatecCredentials_empty(
78
            in SipUserProfile p_userprofile,
79
            in boolean p_algorithm := false
80
        ) return Credentials  {
584 garciay 81
            var Credentials v_result;
607 nikolajev 82
 
599 tepelmann 83
 
84
            // RFC 2617 3.2.2 username:
85
            // The name of user in the specified realm.
584 garciay 86
            var charstring v_username := p_userprofile.privUsername;
87
            var charstring v_realm := p_userprofile.registrarDomain;
88
            var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain;
595 nikolajev 89
            var CommaParam_List v_digestResponse := {};
599 tepelmann 90
            // Construct credentials for an Authorization field of a request.
91
            v_digestResponse[0] := {
92
                id := "username",
93
                paramValue := v_username
94
            };
95
            v_digestResponse[1] := {
96
                id := "realm",
97
                paramValue := v_realm
98
            };
99
            v_digestResponse[2] := {
100
                id := "uri",
101
                paramValue := v_uri
102
            };
103
            v_digestResponse[3] := {
104
                id := "nonce=""""",
105
                paramValue := omit
106
            }; // already enclosed to " characters
107
            v_digestResponse[4] := {
108
                id := "response=""""",
109
                paramValue := omit
607 nikolajev 110
            }; // already enclosed to " characters
599 tepelmann 111
 
595 nikolajev 112
            if (p_algorithm) {
599 tepelmann 113
                v_digestResponse[5] := {
114
                    id := "algorithm",
115
                    paramValue := PX_AUTH_ALGORITHM
607 nikolajev 116
                }; // already enclosed to " characters
584 garciay 117
            }
599 tepelmann 118
            v_result := {digestResponse := v_digestResponse};
119
 
584 garciay 120
            return v_result;
121
        }
9 rennoch 122
 
123
 
584 garciay 124
        /**
125
         * @desc Function to calculate credentials for request that has an empty entity body such as a REGISTER message.
126
         * @param p_userprofile to get important parameters
127
         * @param p_method (can be "REGISTER", "INVITE",....)
128
         * @param p_challenge parameter from 4xx response
129
         * @return Credentials field
130
         * @verdict
131
         */
599 tepelmann 132
        function f_calculatecCredentials(
133
            in SipUserProfile p_userprofile,
134
            in charstring p_method,
135
            in CommaParam_List p_challenge
136
        ) return Credentials  {
584 garciay 137
            var Credentials v_result;
138
            var charstring v_nonce := "";
599 tepelmann 139
            // TODO STF471 change: different cnonce value, e.g. in register and de-register
584 garciay 140
            var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265);
141
 
599 tepelmann 142
            // RFC 2617 3.2.2 username:
143
            // The name of user in the specified realm.
584 garciay 144
            var charstring v_username := p_userprofile.privUsername;
145
            var charstring v_realm;
146
 
599 tepelmann 147
            // RFC 2617 3.2.2.2 passwd:
148
            // A known shared secret, the password of user of the specified
149
            // username.
584 garciay 150
            var charstring v_passwd := p_userprofile.passwd;
151
            var charstring v_algorithm;
152
 
599 tepelmann 153
            // TODO STF471 change: needs to be checked!!!
154
            // correct way would be to increase c_nonceCount depending on used nonce value
155
            // see RFC 2617, where it is stated, that nonce-count has to be incremented
156
            // every time UE uses the same nonce
607 nikolajev 157
            const charstring cl_nonceCount := "00000001";
584 garciay 158
            var charstring v_qop := p_userprofile.qop;
159
            var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain;
160
 
599 tepelmann 161
            // MD5 hash of empty entity body.
607 nikolajev 162
            const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e";
584 garciay 163
            var charstring v_response;
164
            var charstring v_opaque;
599 tepelmann 165
            var CommaParam_List v_digestResponse := {};
584 garciay 166
 
167
 
599 tepelmann 168
            // extract nonce, realm, algorithm, and opaque from challenge
584 garciay 169
            v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce");
170
            v_realm := f_extractParamValueFromChallenge(p_challenge, "realm");
171
            v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm");
172
            v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque");
173
 
599 tepelmann 174
            // calculate a digest response for the Authorize header
607 nikolajev 175
            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);
584 garciay 176
 
599 tepelmann 177
            // Construct credentials for an Authorization field of a request.
178
            // TODO STF471 change: avoid setting absent opaque value
179
            v_digestResponse[0] := {
180
                id := "username",
181
                paramValue := v_username
182
            };
183
            v_digestResponse[1] := {
184
                id := "realm",
185
                paramValue := v_realm
186
            };
187
            v_digestResponse[2] := {
188
                id := "nonce",
189
                paramValue := v_nonce
190
            };
191
            v_digestResponse[3] := {
192
                id := "uri",
193
                paramValue := v_uri
194
            };
195
            v_digestResponse[4] := {
196
                id := "response",
197
                paramValue := v_response
198
            };
199
            v_digestResponse[5] := {
200
                id := "algorithm=md5",
201
                paramValue := omit
202
            }; // algorithm is not enclosed to " characters
203
            v_digestResponse[6] := {
204
                id := "cnonce",
205
                paramValue := v_cnonce
206
            };
207
 
208
            if (v_opaque == "") {
209
                v_digestResponse[7] := {
210
                    id := "qop=" & v_qop,
211
                    paramValue := omit
212
                }; // qop
213
                v_digestResponse[8] := {
607 nikolajev 214
                    id := "nc=" & cl_nonceCount,
599 tepelmann 215
                    paramValue := omit
216
                }; // nonceCount
553 rennoch 217
            }
599 tepelmann 218
            else {
219
                v_digestResponse[7] := {
220
                    id := "opaque",
221
                    paramValue := v_opaque
222
                }; // already enclosed to " characters
223
                v_digestResponse[8] := {
224
                    id := "qop=" & v_qop,
225
                    paramValue := omit
226
                }; // qop
227
                v_digestResponse[9] := {
607 nikolajev 228
                    id := "nc=" & cl_nonceCount,
599 tepelmann 229
                    paramValue := omit
230
                }; // nonceCount
231
            }
232
            v_result := {digestResponse := v_digestResponse};
9 rennoch 233
 
584 garciay 234
            return v_result;
235
        }
9 rennoch 236
 
584 garciay 237
        /**
238
         * @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!
239
         * @param p_userprofile to get important parameters
240
         * @param p_method (can be "REGISTER", "INVITE",....)
241
         * @param p_challenge parameter from 4xx response
242
         * @return Credentials field
243
         * @verdict
244
         */
599 tepelmann 245
        function f_calculatecCredentials_wo_response(
246
            in SipUserProfile p_userprofile,
247
            in charstring p_method,
248
            in CommaParam_List p_challenge
249
        ) return Credentials  {
584 garciay 250
            var Credentials v_result;
251
            var charstring v_nonce := "";
553 rennoch 252
 
599 tepelmann 253
            // TODO STF471 change: different cnonce value, e.g. in register and de-register
584 garciay 254
            var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265);
9 rennoch 255
 
599 tepelmann 256
            // RFC 2617 3.2.2 username:
257
            // The name of user in the specified realm.
584 garciay 258
            var charstring v_username := p_userprofile.privUsername;
259
            var charstring v_realm;
553 rennoch 260
 
599 tepelmann 261
            // RFC 2617 3.2.2.2 passwd:
262
            // A known shared secret, the password of user of the specified
263
            // username.
584 garciay 264
            var charstring v_passwd := p_userprofile.passwd;
265
            var charstring v_algorithm;
266
 
267
 
599 tepelmann 268
            // TODO STF471 change: needs to be checked!!!
269
            // correct way would be to increase c_nonceCount depending on used nonce value
270
            // see RFC 2617, where it is stated, that nonce-count has to be incremented
271
            // every time UE uses the same nonce
607 nikolajev 272
            const charstring cl_nonceCount := "00000001";
584 garciay 273
            var charstring v_qop := p_userprofile.qop;
274
            var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain;
275
 
599 tepelmann 276
            // MD5 hash of empty entity body.
607 nikolajev 277
            const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e";
584 garciay 278
            var charstring v_response;
279
            var charstring v_opaque;
599 tepelmann 280
            var CommaParam_List v_digestResponse := {};
584 garciay 281
 
599 tepelmann 282
            // extract nonce, realm, algorithm, and opaque from challenge
584 garciay 283
            v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce");
284
            v_realm := f_extractParamValueFromChallenge(p_challenge, "realm");
285
            v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm");
286
            v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque");
287
 
599 tepelmann 288
            // calculate a digest response for the Authorize header
607 nikolajev 289
            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);
584 garciay 290
 
599 tepelmann 291
            // TODO STF471 change: avoid setting absent opaque value
292
            v_digestResponse[0] := {
293
                id := "username",
294
                paramValue := v_username
295
            };
296
            v_digestResponse[1] := {
297
                id := "realm",
298
                paramValue := v_realm
299
            };
300
            v_digestResponse[2] := {
301
                id := "nonce",
302
                paramValue := v_nonce
303
            };
304
            v_digestResponse[3] := {
305
                id := "uri",
306
                paramValue := v_uri
307
            };
308
            v_digestResponse[4] := {
309
                id := "algorithm=md5",
310
                paramValue := omit
311
            }; // algorithm is not enclosed to " characters
312
            v_digestResponse[5] := {
313
                id := "cnonce",
314
                paramValue := v_cnonce
315
            };
316
 
584 garciay 317
            if (v_opaque == "") {
599 tepelmann 318
                v_digestResponse[6] := {
319
                    id := "qop=" & v_qop,
320
                    paramValue := omit
321
                }; // qop
322
                v_digestResponse[7] := {
607 nikolajev 323
                    id := "nc=" & cl_nonceCount,
599 tepelmann 324
                    paramValue := omit
325
                }; // nonceCount
584 garciay 326
            }
599 tepelmann 327
            else {
328
                v_digestResponse[6] := {
329
                    id := "opaque",
330
                    paramValue := v_opaque
331
                }; // already enclosed to " characters
332
                v_digestResponse[7] := {
333
                    id := "qop=" & v_qop,
334
                    paramValue := omit
335
                }; // qop
336
                v_digestResponse[8] := {
607 nikolajev 337
                    id := "nc=" & cl_nonceCount,
599 tepelmann 338
                    paramValue := omit
339
                }; // nonceCount
340
            }
341
            v_result := {digestResponse := v_digestResponse};
584 garciay 342
 
343
            return v_result;
553 rennoch 344
        }
9 rennoch 345
 
584 garciay 346
        /**
347
         * @desc Function to calculate credentials for response 401 - WWW-Authorization
348
         * @param p_qop of the peer UE (alternatively )
349
         * @param p_authorization parameter from 1st REGISTER request
350
         * @return Credentials field
351
         * @verdict
352
         */
599 tepelmann 353
        function f_calculatecChallenge_forWWWAuthorizationBody(
354
            in charstring p_qop,
355
            in Authorization p_authorization
356
        ) return Challenge  {
584 garciay 357
            var CommaParam_List v_challenge;
9 rennoch 358
 
584 garciay 359
            if (ischosen(p_authorization.body[0].digestResponse)) {
360
                v_challenge := p_authorization.body[0].digestResponse;
599 tepelmann 361
            }
362
            else {
584 garciay 363
                v_challenge := p_authorization.body[0].otherResponse.authParams;
364
            }
9 rennoch 365
 
584 garciay 366
            return (f_calculatecChallenge_forWWWAuthorization(p_qop, v_challenge));
367
        }
9 rennoch 368
 
584 garciay 369
        /**
370
         * @desc Function to calculate credentials for response 401 - WWW-Authorization
371
         * @param p_qop of the peer UE (alternatively )
372
         * @param p_challenge parameter from 1st REGISTER request
373
         * @return Credentials field
374
         * @verdict
375
         */
599 tepelmann 376
        function f_calculatecChallenge_forWWWAuthorization(
377
            in charstring p_qop,
378
            in CommaParam_List p_challenge
379
        ) return Challenge  {
584 garciay 380
            var Challenge v_result;
9 rennoch 381
 
584 garciay 382
            var charstring v_realm;
9 rennoch 383
 
584 garciay 384
            var charstring v_qop := p_qop;
9 rennoch 385
 
584 garciay 386
            v_realm := f_extractParamValueFromChallenge(p_challenge, "realm");
9 rennoch 387
 
599 tepelmann 388
            // Construct credentials for an Authorization field of a request.
584 garciay 389
            v_result := {
390
                digestCln := {
599 tepelmann 391
                    {
392
                        id := "realm",
393
                        paramValue := v_realm
394
                    },
395
                    {
396
                        id := "nonce",
397
                        paramValue := "0edff6c521cc3f407f2d9e01cf6ed82b"
398
                    },
399
                    {
400
                        id := "algorithm",
401
                        paramValue := PX_AUTH_ALGORITHM
402
                    },  // algorithm is not enclosed with " characters
403
                    {
404
                        id := "ck",
405
                        paramValue := "00112233445566778899aabbccddeeff"
406
                    },
407
                    {
408
                        id := "ik",
409
                        paramValue := "ffeeddccbbaa99887766554433221100"
410
                    },  // already enclosed to " characters
411
                    // TODO STF471 change: check why v_qop was not a paramValue!!!
412
                    {
413
                        id := "qop",
414
                        paramValue := v_qop
415
                    } // qop
584 garciay 416
                }
417
            };
9 rennoch 418
 
584 garciay 419
            return v_result;
420
        }
403 poglitsch 421
 
584 garciay 422
        /**
599 tepelmann 423
         * @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
584 garciay 424
         * @param p_userprofile to get important parameters
425
         * @param p_method (can be "REGISTER", "INVITE",....)
426
         * @param p_challenge parameter from 4xx response
427
         * @return Credentials field
428
         * @verdict
429
         */
599 tepelmann 430
        function f_calculatecCredentialsAndChangeUserName(
431
            in SipUserProfile p_userprofile,
432
            in charstring p_method,
433
            in CommaParam_List p_challenge
434
        ) return Credentials  {
584 garciay 435
            var Credentials v_result;
436
            var charstring v_nonce := "";
9 rennoch 437
 
599 tepelmann 438
            // TODO STF471 change: different cnonce value, e.g. in register and de-register
584 garciay 439
            var charstring v_cnonce := int2str(float2int(int2float(13172657659 - 1317266) * rnd()) + 1317265);
9 rennoch 440
 
599 tepelmann 441
            // RFC 2617 3.2.2 username:
442
            // The name of user in the specified realm.
584 garciay 443
            var charstring v_username := p_userprofile.privUsername;
444
            var charstring v_realm;
9 rennoch 445
 
599 tepelmann 446
            // RFC 2617 3.2.2.2 passwd:
447
            // A known shared secret, the password of user of the specified
448
            // username.
584 garciay 449
            var charstring v_passwd := p_userprofile.passwd;
450
            var charstring v_algorithm;
403 poglitsch 451
 
452
 
599 tepelmann 453
            // TODO STF471 change: needs to be checked!!!
454
            // correct way would be to increase c_nonceCount depending on used nonce value
455
            // see RFC 2617, where it is stated, that nonce-count has to be incremented
456
            // every time UE uses the same nonce
607 nikolajev 457
            const charstring cl_nonceCount := "00000001";
584 garciay 458
            var charstring v_qop := p_userprofile.qop;
459
            var charstring v_uri := c_sipScheme & ":" & p_userprofile.registrarDomain;
9 rennoch 460
 
461
 
599 tepelmann 462
            // MD5 hash of empty entity body.
607 nikolajev 463
            const charstring cl_hEntity := "d41d8cd98f00b204e9800998ecf8427e";
584 garciay 464
            var charstring v_response;
465
            var charstring v_opaque;
595 nikolajev 466
            var CommaParam_List v_digestResponse := {};
9 rennoch 467
 
468
 
599 tepelmann 469
            // extract nonce, realm, algorithm, and opaque from challenge
584 garciay 470
            v_nonce := f_extractParamValueFromChallenge(p_challenge, "nonce");
471
            v_realm := f_extractParamValueFromChallenge(p_challenge, "realm");
472
            v_algorithm := f_extractParamValueFromChallenge(p_challenge, "algorithm");
473
            v_opaque := f_extractParamValueFromChallenge(p_challenge, "opaque");
9 rennoch 474
 
599 tepelmann 475
            // calculate a digest response for the Authorize header
607 nikolajev 476
            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);
9 rennoch 477
 
599 tepelmann 478
            // Construct credentials for an Authorization field of a request.
479
            // TODO STF471 change: avoid setting absent opaque value
480
            v_digestResponse[0] := {
481
                id := "username",
482
                paramValue := "DifferentToPrivateUser"
483
            };
484
            v_digestResponse[1] := {
485
                id := "realm",
486
                paramValue := v_realm
487
            };
488
            v_digestResponse[2] := {
489
                id := "nonce",
490
                paramValue := v_nonce
491
            };
492
            v_digestResponse[3] := {
493
                id := "uri",
494
                paramValue := v_uri
495
            };
496
            v_digestResponse[4] := {
497
                id := "response",
498
                paramValue := v_response
499
            };
500
            v_digestResponse[5] := {
501
                id := "algorithm=md5",
502
                paramValue := omit
503
            }; // algorithm is not enclosed to " characters
504
            v_digestResponse[6] := {
505
                id := "cnonce",
506
                paramValue := v_cnonce
507
            };
595 nikolajev 508
 
584 garciay 509
            if (v_opaque == "") {
599 tepelmann 510
                v_digestResponse[7] := {
511
                    id := "qop=" & v_qop,
512
                    paramValue := omit
513
                }; // qop
514
                v_digestResponse[8] := {
607 nikolajev 515
                    id := "nc=" & cl_nonceCount,
599 tepelmann 516
                    paramValue := omit
517
                };
584 garciay 518
            }
599 tepelmann 519
            else {
520
                v_digestResponse[7] := {
521
                    id := "opaque=""""",
522
                    paramValue := omit
523
                }; // already enclosed to " characters
524
                v_digestResponse[8] := {
525
                    id := "qop=" & v_qop,
526
                    paramValue := omit
527
                }; // qop
528
                v_digestResponse[9] := {
607 nikolajev 529
                    id := "nc=" & cl_nonceCount,
599 tepelmann 530
                    paramValue := omit
531
                };
532
            }
533
            v_result := {digestResponse := v_digestResponse};
9 rennoch 534
 
584 garciay 535
            return v_result;
536
        }
9 rennoch 537
 
538
 
584 garciay 539
        /**
540
         * @desc Function to check if param related to id from CommanParam_List exist containing challenge.
541
         * @param p_challenge parameter from 4xx response
542
         * @param p_id name of parameter("nonce", "realm", "ck", "ik"...)
543
         * @return parameter p_id value
544
         */
599 tepelmann 545
        function f_checkParamValueFromChallengeIfPresent(
546
            in CommaParam_List p_challenge,
547
            in charstring p_id
548
        ) return boolean  {
584 garciay 549
            var boolean v_result := false;
550
            var integer v_len := lengthof(p_challenge);
551
            var charstring v_id := fx_putInLowercase(p_id);
607 nikolajev 552
            var integer i;
553
 
554
            for (i := 0; i < v_len; i := i + 1) {
584 garciay 555
                if (fx_putInLowercase(p_challenge[i].id) == v_id) {
556
                    v_result := true;
557
                }
558
            }
9 rennoch 559
 
584 garciay 560
            return v_result;
561
        }
403 poglitsch 562
 
584 garciay 563
        /**
564
         * @desc Function to check if tag is present in SemicolonParam_List
565
         * @param p_param_l SemicolonParam_List
566
         * @return boolean true if tag is present
567
         */
600 nikolajev 568
        function f_checkTagPresent(
569
            SemicolonParam_List p_param_l
570
        ) runs on SipComponent
571
        return boolean  {
584 garciay 572
            var integer v_numberOfParams;
573
            var integer i := 0;
403 poglitsch 574
 
584 garciay 575
            v_numberOfParams := lengthof(p_param_l);
576
            while (i < v_numberOfParams) {
577
                if (fx_putInLowercase(p_param_l[i].id) == c_tagId) {
578
                    return (true);
579
                }
580
                i := i + 1;
581
            }
582
            return (false);
583
        }
9 rennoch 584
 
599 tepelmann 585
        // TODO STF471 change: use this function, e.g. in calculateCredentials...!!!
584 garciay 586
        /**
587
         * @desc Function to remove a parameter from SemicolonParam_List
588
         * @param p_param_l SemicolonParam_List
589
         * @return SemicolonParam_List new parameter list
590
         */
599 tepelmann 591
        function f_removeParameter(
592
            SemicolonParam_List p_param_l,
593
            charstring p_id
600 nikolajev 594
        ) runs on SipComponent
595
        return SemicolonParam_List  {
584 garciay 596
            var integer v_numberOfParams;
597
            var integer i := 0;
598
            var integer j := 0;
599
            var SemicolonParam_List v_newParamList;
9 rennoch 600
 
584 garciay 601
            v_numberOfParams := lengthof(p_param_l);
602
            while (i < v_numberOfParams) {
603
                if (not fx_putInLowercase(p_param_l[i].id) == p_id) {
604
                    v_newParamList[j] := p_param_l[i];
605
                    j := j + 1;
606
                }
607
                i := i + 1;
608
            }
609
            return v_newParamList;
610
        }
9 rennoch 611
 
599 tepelmann 612
        // TODO STF471 change: use this function, e.g. in calculateCredentials...!!!
584 garciay 613
        /**
614
         * @desc Function to add a parameter to SemicolonParam_List
615
         * @param p_param_l SemicolonParam_List
616
         * @return SemicolonParam_List new parameter list
617
         */
599 tepelmann 618
        function f_addParameter(
619
            SemicolonParam_List p_param_l,
620
            GenericParam p_genparam
600 nikolajev 621
        ) runs on SipComponent
622
        return SemicolonParam_List  {
584 garciay 623
            var SemicolonParam_List v_newParamList := p_param_l;
624
            var integer v_numberOfParams := lengthof(p_param_l);
625
            v_newParamList[v_numberOfParams] := p_genparam;
348 rennoch 626
 
584 garciay 627
            return v_newParamList;
628
        }
414 pintar 629
 
584 garciay 630
        /**
631
         * @desc Function to extract paramValue related to id from CommanParam_List containing challenge.
632
         * @param p_challenge parameter from 4xx response
633
         * @param p_id name of parameter("nonce", "realm",...)
634
         * @return parameter p_id value
635
         */
599 tepelmann 636
        function f_extractParamValueFromChallenge(
637
            in CommaParam_List p_challenge,
638
            in charstring p_id
639
        ) return charstring  {
584 garciay 640
            var charstring v_result := "";
641
            var integer v_len := lengthof(p_challenge);
642
            var charstring v_id := fx_putInLowercase(p_id);
607 nikolajev 643
            var integer i;
644
            var charstring v_tmpchar;
414 pintar 645
 
607 nikolajev 646
            for (i := 0; i < v_len; i := i + 1) {
584 garciay 647
                if (fx_putInLowercase(p_challenge[i].id) == v_id) {
648
                    if (isvalue(p_challenge[i].paramValue)) {
649
                        v_result := valueof(p_challenge[i].paramValue);
650
                    }
651
                }
652
            }
350 saiu 653
 
584 garciay 654
            if (v_result == "") {
655
                if (match(p_id, "algorithm")) {
656
                    v_result := "MD5";
599 tepelmann 657
                }
658
                else if (match(p_id, "opaque")) {
584 garciay 659
                    v_result := "";
599 tepelmann 660
                }
661
                else {
607 nikolajev 662
                    v_tmpchar := "Cannot acquire value from credentials.";
608 nikolajev 663
                    log("*** " & __SCOPE__ &": INFO: Cannot acquire value from credentials ***");
584 garciay 664
                    setverdict(inconc);
665
                    stop;
666
                }
667
            }
350 saiu 668
 
584 garciay 669
            return v_result;
670
        }
9 rennoch 671
 
599 tepelmann 672
        // TODO STF471 added, check location
584 garciay 673
        /**
674
         * @desc Return the updated component variable of via header
675
         * @return component variable of via header
676
         */
600 nikolajev 677
        function f_updateViaHeaderAS(
607 nikolajev 678
            in Via p_via
600 nikolajev 679
        ) runs on SipComponent
680
        return Via  {
607 nikolajev 681
            var Via v_via;
682
            var ViaBody_List v_viaBody_List := p_via.viaBody;
683
            var integer v_size_via := lengthof(v_viaBody_List);
684
            var integer v_size_via_updated := v_size_via + 1;
685
            var ViaBody_List v_viaBody_List_updated;
686
            var integer i;
584 garciay 687
            vc_branch := c_branchCookie & f_getRndTag();
607 nikolajev 688
            v_viaBody_List_updated[0] := valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile));
599 tepelmann 689
            // p_viaBody_List_updated[0 ] := vc_request.msgHeader.route.routeBody[0 ] ;
607 nikolajev 690
            for (i := 1; i < v_size_via_updated; i := i + 1) {
691
                v_viaBody_List_updated[i] := v_viaBody_List[i - 1];
584 garciay 692
            }
607 nikolajev 693
            v_via.fieldName := p_via.fieldName;
694
            v_via.viaBody := v_viaBody_List_updated;
695
            return (v_via);
584 garciay 696
        }
88 poglitsch 697
 
599 tepelmann 698
        // TODO STF471 added, check location
584 garciay 699
        /**
700
         * @desc Return the updated component variable of route header
701
         * @return component variable of route header
702
         */
600 nikolajev 703
        function f_updateRouteHeaderAS(
607 nikolajev 704
            in Route p_route
600 nikolajev 705
        ) runs on SipComponent
706
        return Route  {
607 nikolajev 707
            var Route v_route;
708
            var RouteBody_List v_routeBody_List := p_route.routeBody;
709
            var integer v_size_route := lengthof(v_routeBody_List);
710
            var integer v_size_route_updated := v_size_route - 1;
711
            var RouteBody_List v_routeBody_List_updated;
712
            var integer i;
88 poglitsch 713
 
607 nikolajev 714
            for (i := 0; i < v_size_route_updated; i := i + 1) {
715
                v_routeBody_List_updated[i] := v_routeBody_List[i + 1];
584 garciay 716
            }
607 nikolajev 717
            v_route.fieldName := p_route.fieldName;
718
            v_route.routeBody := v_routeBody_List_updated;
719
            return (v_route);
584 garciay 720
        }
9 rennoch 721
 
599 tepelmann 722
        // TODO STF471 added, check location
584 garciay 723
        /**
724
         * @desc Return the updated component variable of record route header
725
         * @return component variable of record route header
726
         */
600 nikolajev 727
        function f_updateRecordRouteHeaderAS(
728
            in template(value) RecordRoute p_recordRoute
729
        ) runs on SipComponent
730
        return RecordRoute  {
599 tepelmann 731
            var
732
            RecordRoute
733
                v_recordRoute :=
734
                valueof(
735
                    m_recordRoute_currIpAddr_params(
736
                        vc_userprofile,
737
                        {
738
                            {
739
                                "lr",
740
                                omit
741
                            }
742
                        }
743
                    )
744
                );
607 nikolajev 745
            var integer v_size_recordRoute := 0;
746
            var integer i;
407 pintar 747
 
584 garciay 748
            if (isvalue(p_recordRoute)) {
607 nikolajev 749
                v_size_recordRoute := lengthof(valueof(p_recordRoute).routeBody);
584 garciay 750
            }
607 nikolajev 751
            for (i := 1; i < v_size_recordRoute + 1; i := i + 1) {
584 garciay 752
                v_recordRoute.routeBody[i] := valueof(p_recordRoute).routeBody[i - 1];
753
            }
9 rennoch 754
 
584 garciay 755
            return (v_recordRoute);
756
        }
9 rennoch 757
 
502 pintar 758
 
599 tepelmann 759
 
584 garciay 760
    } // end group ParameterOperations
761
 
762
    group FieldOperations {
763
 
764
        /**
765
         * @desc function adds "Tag"-parameter in "To"-headerfield
766
         * @param p_to To header field that should get a Tag parameter
767
         */
600 nikolajev 768
        function f_addTagInTo(
769
            inout To p_to
770
        ) runs on SipComponent  {
584 garciay 771
            f_addParameterTagIfNotPresent(c_tagId, f_getRndTag(), p_to);
502 pintar 772
        }
9 rennoch 773
 
584 garciay 774
        /**
775
         * @desc addition of a single parameter in the via header field
776
         * @param p_parameter_name name of parameter to be added
777
         * @param p_parameter_value value of parameter to be added
778
         * @param p_viaBody the via parameter to be extended
779
         * @verdict
780
         */
599 tepelmann 781
        function f_addParameterIfNotPresent(
782
            in charstring p_parameter_name,
783
            in charstring p_parameter_value,
784
            inout ViaBody p_viaBody
785
        ) {
584 garciay 786
            if (isvalue(p_viaBody.viaParams)) {
787
                return;
788
            }
599 tepelmann 789
            p_viaBody.viaParams := {
790
                {
791
                    p_parameter_name,
792
                    p_parameter_value
793
                }
794
            };
584 garciay 795
        }
9 rennoch 796
 
584 garciay 797
        /**
798
         * @desc function to addd a parameter to the "To" header field (if there is not any parameter)
799
         * @param p_parameter_name name of the parameter to be added
800
         * @param p_parameter_value value of the paramter to be added
801
         * @param p_to "To" header field to be extended
802
         * @verdict
803
         */
599 tepelmann 804
        function f_addParameterTagIfNotPresent(
805
            in charstring p_parameter_name,
806
            in charstring p_parameter_value,
807
            inout To p_to
808
        ) {
584 garciay 809
            if (isvalue(p_to.toParams)) {
810
                return;
811
            }
599 tepelmann 812
            p_to.toParams := {
813
                {
814
                    p_parameter_name,
815
                    p_parameter_value
816
                }
817
            };
584 garciay 818
        }
9 rennoch 819
 
584 garciay 820
        /**
821
         * @desc function compares the IP address of two hosts
822
         * @param p_host1 hostname
823
         * @param p_host2 hostname
824
         * @return boolean value that is true if the IP addresses are identical
825
         * @verdict
826
         */
599 tepelmann 827
        function f_equivalentHostAddr(
828
            in charstring p_host1,
829
            in charstring p_host2
830
        ) return boolean  {
831
            // A DNS server may be used
584 garciay 832
            return (fx_getIpAddr(p_host1) == fx_getIpAddr(p_host2));
833
        }
9 rennoch 834
 
835
 
584 garciay 836
        /**
837
         * @desc function checks if Require contains Precondition
838
         * @param p_message (request or response) SIP message to be analysed
839
         * @return true if p_id parameter exist
840
         */
600 nikolajev 841
        function f_checkRequirePrecondition(
842
            in Request p_message
843
        ) {
607 nikolajev 844
            var boolean v_precondition_found;
845
            var integer i;
584 garciay 846
            if (isvalue(p_message.msgHeader.require)) {
607 nikolajev 847
                v_precondition_found := false;
848
                for (i := 0; i < lengthof(p_message.msgHeader.require.optionsTags); i := i + 1) {
849
                    if (match(p_message.msgHeader.require.optionsTags[i], c_tagPrecond)) {
584 garciay 850
                        v_precondition_found := true;
851
                    }
852
                }
853
                if (not (v_precondition_found)) {
854
                    setverdict(fail);
608 nikolajev 855
                    log("*** " & __SCOPE__ & ": FAIL: precondition not found in Require options list! ***");
584 garciay 856
                }
599 tepelmann 857
            }
858
            else {
584 garciay 859
                setverdict(fail);
608 nikolajev 860
                log("*** " & __SCOPE__ & ": FAIL: Require options is not present! ***");
584 garciay 861
            }
862
        }
9 rennoch 863
 
584 garciay 864
        /**
865
         * @desc function checks if P-Charging-Vector contains a particular parameter
866
         * @param p_message (request or response) SIP message to be analysed
867
         * @param p_id name of parameter
868
         * @return true if p_id parameter exist
869
         */
599 tepelmann 870
        function f_checkPChargingVectorHeaderParamId(
871
            in Request p_message,
872
            charstring p_id
873
        ) return boolean  {
607 nikolajev 874
            var integer i;
9 rennoch 875
 
584 garciay 876
            if (isvalue(p_message.msgHeader.pChargingVector)) {
607 nikolajev 877
                for (i := 0; i < lengthof(p_message.msgHeader.pChargingVector.chargeParams); i := i + 1) {
584 garciay 878
                    if (p_message.msgHeader.pChargingVector.chargeParams[i].id == p_id) {
879
                        return (true);
880
                    }
881
                }
882
            }
883
            return (false);
884
        }
9 rennoch 885
 
584 garciay 886
        /**
887
         * @desc function checks if P-Charging-Vector contains a particular parameter
888
         * @param p_message (request or response) SIP message to be analysed
889
         * @param p_id name of parameter
890
         * @return true if p_id parameter exist
891
         */
599 tepelmann 892
        function f_checkPChargingVectorHeaderParamIdResponse(
893
            in Response p_message,
894
            charstring p_id
895
        ) return boolean  {
607 nikolajev 896
            var integer i;
9 rennoch 897
 
584 garciay 898
            if (isvalue(p_message.msgHeader.pChargingVector)) {
607 nikolajev 899
                for (i := 0; i < lengthof(p_message.msgHeader.pChargingVector.chargeParams); i := i + 1) {
584 garciay 900
                    if (p_message.msgHeader.pChargingVector.chargeParams[i].id == p_id) {
901
                        return true;
902
                    }
903
                }
904
            }
905
            return (false);
906
        }
9 rennoch 907
 
584 garciay 908
        /**
909
         * @desc function returns the Host/Port of a given Contact header field
910
         * @param p_contact contact header field to be analysed
911
         * @return Host/Port record from the contact header field
912
         */
600 nikolajev 913
        function f_getContactUri(
914
            in ContactAddress p_contact
915
        ) runs on SipComponent
916
        return SipUrl  {
584 garciay 917
            var SipUrl v_SipUrl;
9 rennoch 918
 
584 garciay 919
            if (ischosen(p_contact.addressField.nameAddr)) {
920
                v_SipUrl := p_contact.addressField.nameAddr.addrSpec;
599 tepelmann 921
            }
922
            else {
584 garciay 923
                v_SipUrl := p_contact.addressField.addrSpecUnion;
924
            }
9 rennoch 925
 
584 garciay 926
            return (v_SipUrl);
927
        } // end f_getContactUri
9 rennoch 928
 
584 garciay 929
        /**
930
         * @desc function returns the Host/Port of a given Contact header field
931
         * @param p_contact contact header field to be analysed
932
         * @return Host/Port record from the contact header field
933
         */
600 nikolajev 934
        function f_getContactAddr(
935
            in ContactAddress p_contact
936
        ) runs on SipComponent
937
        return HostPort  {
584 garciay 938
            var HostPort v_locAddr;
939
            var SipUrl v_SipUrl;
9 rennoch 940
 
584 garciay 941
            if (ischosen(p_contact.addressField.nameAddr)) {
942
                v_SipUrl := p_contact.addressField.nameAddr.addrSpec;
599 tepelmann 943
            }
944
            else {
584 garciay 945
                v_SipUrl := p_contact.addressField.addrSpecUnion;
946
            }
9 rennoch 947
 
584 garciay 948
            v_locAddr.host := v_SipUrl.components.sip.hostPort.host;
9 rennoch 949
 
584 garciay 950
            if (isvalue(v_SipUrl.components.sip.hostPort.portField)) {
951
                v_locAddr.portField := v_SipUrl.components.sip.hostPort.portField;
599 tepelmann 952
            }
953
            else {
584 garciay 954
                v_locAddr.portField := c_defaultSipPort;
955
            }
9 rennoch 956
 
584 garciay 957
            return (v_locAddr);
958
        } // end f_getContactAddr
9 rennoch 959
 
584 garciay 960
        /**
961
         * @desc function checks if History-Info-Header of the p_message contains a particular URI
962
         * @param p_message (request or response) SIP message to be analysed
963
         * @param p_URI name of parameter
964
         * @return true if p_URI parameter exist
965
         */
599 tepelmann 966
        function f_checkHeaderInfoURI(
967
            in Response p_message,
968
            SipUrl p_URI
969
        ) return boolean  {
607 nikolajev 970
            var integer i;
9 rennoch 971
 
584 garciay 972
            if (isvalue(p_message.msgHeader.historyInfo)) {
607 nikolajev 973
                for (i := 0; i < lengthof(p_message.msgHeader.historyInfo.historyInfoList); i := i + 1) {
584 garciay 974
                    if (p_message.msgHeader.historyInfo.historyInfoList[i].nameAddr.addrSpec == p_URI) {
975
                        return (true);
976
                    }
977
                }
978
            }
979
            return (false);
980
        }
393 pintar 981
 
584 garciay 982
        /**
983
         * @desc function returns the Userinfo from a given To header field
984
         * @param p_to To header field to be analysed
985
         * @return Userinfo from the To header field as a charstring
986
         */
600 nikolajev 987
        function f_getUserfromTo(
988
            in To p_to
989
        ) runs on SipComponent
990
        return charstring  {
584 garciay 991
            var SipUrl v_SipUrl;
393 pintar 992
 
584 garciay 993
            if (ischosen(p_to.addressField.nameAddr)) {
994
                v_SipUrl := p_to.addressField.nameAddr.addrSpec;
599 tepelmann 995
            }
996
            else {
584 garciay 997
                v_SipUrl := p_to.addressField.addrSpecUnion;
998
            }
9 rennoch 999
 
584 garciay 1000
            return (v_SipUrl.components.sip.userInfo.userOrTelephoneSubscriber);
1001
        } // end f_getUserfromTo
1002
 
1003
        /**
1004
         * @desc function to generate a 32 bits random number as a charstring for tag field
1005
         * @param p_cSeq_s CSeq parameter used to modify the tag field value
1006
         * @return tag value
1007
         */
600 nikolajev 1008
        function f_getRndCallId(
1009
        ) return charstring  {
607 nikolajev 1010
            var charstring v_tag_value := fx_rndStr() & fx_rndStr();
599 tepelmann 1011
            // v_tag_value is initialized with a random value with at least 32 bits of randomness
1012
            // 4294967296 is a 32 bits integer
1013
            // v_tag_value := int2str(float2int(4294967296.0*rnd()) + loc_CSeq_s.seqNumber );
584 garciay 1014
            return (v_tag_value);
1015
        }
1016
 
1017
        /**
1018
         * @desc function give access to the top element of the Path header field.
1019
         * @param p_Request SIP message to be analysed
1020
         * @return NameAddr (e.g. <sip:p.home.com>) or omit
1021
         */
600 nikolajev 1022
        function f_getPathHeaderTop(
1023
            inout Request p_Request
1024
        ) return template(omit) NameAddr  {
584 garciay 1025
            if (isvalue(p_Request.msgHeader.path)) {
1026
                if (lengthof(p_Request.msgHeader.path.pathValues) > 0) {
1027
                    return (p_Request.msgHeader.path.pathValues[0].nameAddr);
1028
                }
1029
            }
1030
            return (omit);
1031
        }
1032
 
1033
        /**
1034
         * @desc function updates first element of a Via headerfield list
1035
         * @param p_viaBody_List address list of a Via header field
1036
         * @param p_source_address address to be inserted in the top element
1037
         */
599 tepelmann 1038
        function f_getViaReplyAddr(
1039
            inout ViaBody_List p_viaBody_List,
607 nikolajev 1040
            inout Address4SIP p_source_address
599 tepelmann 1041
        ) runs on SipComponent  {
584 garciay 1042
            var ViaBody v_viaBody;
599 tepelmann 1043
            // The address to send message shall be updated after getting information
1044
            // in the Via header fied and according to 18.2.2
584 garciay 1045
            v_viaBody := p_viaBody_List[0];
1046
 
599 tepelmann 1047
            // received parameter has to be addded to the via hader field
1048
            // Be careful it could be an Host name and not an IP Address
1049
            // TODO STF471 change: check this!!!
1050
            // The error probably occurs if no DNS server is available
1051
            // we have re-added the check, because if no DNS server is available it is possible to adapt the configuration
1052
            // on the local machine the test suite is running on (e.g. under Windows the following file could be configured:
1053
            // C:\WINDOWS\system32\drivers\etc\hosts).
1054
            // TODO produce an error because of unkown host exception
584 garciay 1055
            if (not f_equivalentHostAddr(valueof(v_viaBody.sentBy.host), valueof(p_source_address.host))) {
1056
                f_addParameterIfNotPresent(c_receivedId, valueof(p_source_address.host), v_viaBody);
1057
            }
1058
            if (isvalue(v_viaBody.sentBy.portField)) {
1059
                p_source_address.portField := valueof(v_viaBody.sentBy.portField);
599 tepelmann 1060
            }
1061
            else {
584 garciay 1062
                p_source_address.portField := c_defaultSipPort;
1063
            }
1064
        }
1065
 
1066
        /**
1067
         * @desc functions give access to an element of the Route header field (record).
1068
         * @param p_message (request) SIP message to be analysed
1069
         * @param p_index index of Route record element to be retrieved
1070
         * @return HostPort value of the Route element or omit
1071
         */
599 tepelmann 1072
        function f_getRouteHeaderElementAddressFromRequest(
1073
            in Request p_message,
1074
            in integer p_index
1075
        ) return HostPort  {
584 garciay 1076
            if (isvalue(p_message.msgHeader.route)) {
1077
                if (lengthof(p_message.msgHeader.route.routeBody) > p_index) {
1078
                    return (p_message.msgHeader.route.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort);
1079
                }
1080
            }
1081
            setverdict(fail);
1082
            return (c_hostport_dummy);
1083
        }
1084
 
1085
        /**
1086
         * @desc functions give access to an element of the Record-Route header field (record).
1087
         * @param p_message (request) SIP message to be analysed
1088
         * @param p_index index of recordRoute record element to be retrieved
1089
         * @return HostPort value of the Record-Route element or omit
1090
         */
599 tepelmann 1091
        function f_getRecordRouteHeaderElementAddressFromRequest(
1092
            in Request p_message,
1093
            in integer p_index
1094
        ) return HostPort  {
584 garciay 1095
            if (isvalue(p_message.msgHeader.recordRoute)) {
1096
                if (lengthof(p_message.msgHeader.recordRoute.routeBody) > p_index) {
1097
                    return (p_message.msgHeader.recordRoute.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort);
1098
                }
1099
            }
1100
            setverdict(fail);
1101
            return (c_hostport_dummy);
1102
        }
1103
 
1104
        /**
1105
         * @desc functions give access to an element of the Record-Route header field (record).
1106
         * @param p_message (response) SIP message to be analysed
1107
         * @param p_index index of recordRoute record element to be retrieved
1108
         * @return HostPort value of the Record-Route element or omit
1109
         */
599 tepelmann 1110
        function f_getRecordRouteHeaderElementAddressFromResponse(
1111
            in Response p_message,
1112
            in integer p_index
1113
        ) return HostPort  {
584 garciay 1114
            if (isvalue(p_message.msgHeader.recordRoute)) {
1115
                if (lengthof(p_message.msgHeader.recordRoute.routeBody) > p_index) {
1116
                    return (p_message.msgHeader.recordRoute.routeBody[p_index].nameAddr.addrSpec.components.sip.hostPort);
1117
                }
1118
            }
1119
            setverdict(fail);
1120
            return (c_hostport_dummy);
1121
        }
1122
 
1123
        /**
1124
         * @desc functions give access to an element of the Via header field (record).
1125
         * @param p_message (request) SIP message to be analysed
1126
         * @param p_index index of via record element to be retrieved
1127
         * @return HostPort value of the Via element or omit
1128
         */
599 tepelmann 1129
        function f_getViaHeaderElementHostPort(
1130
            in Request p_message,
1131
            in integer p_index
1132
        ) return HostPort  {
584 garciay 1133
 
1134
            if (lengthof(p_message.msgHeader.via.viaBody) > p_index) {
1135
                return (p_message.msgHeader.via.viaBody[p_index].sentBy);
1136
            }
1137
            setverdict(fail);
1138
            return (c_hostport_dummy);
1139
        }
1140
 
1141
        /**
1142
         * @desc functions give access to an element of the Via header field (record).
1143
         * @param p_message (response) SIP message to be analysed
1144
         * @param p_index index of via record element to be retrieved
1145
         * @return HostPort value of the Via element or omit
1146
         */
599 tepelmann 1147
        function f_getViaHeaderElementHostPortResponse(
1148
            in Response p_message,
1149
            in integer p_index
1150
        ) return HostPort  {
584 garciay 1151
 
1152
            if (lengthof(p_message.msgHeader.via.viaBody) > p_index) {
1153
                return (p_message.msgHeader.via.viaBody[p_index].sentBy);
1154
            }
1155
            setverdict(fail);
1156
            return (c_hostport_dummy);
1157
        }
1158
 
1159
        /**
1160
         * @desc function checks indicators if topology hiding (TH) has been applied: - second element in via-header record has tokenized-by parameter
1161
         * @param p_Request SIP message to be analysed
1162
         * @return boolean value (true indicate TH, false otherwise)
1163
         */
600 nikolajev 1164
        function f_topologyHiding(
1165
            inout Request p_request
1166
        ) runs on SipComponent
1167
        return boolean  {
612 garciay 1168
            var GenericParam v_viaParameter;
1169
 
1170
            if (sizeof(p_request.msgHeader.via.viaBody) <2 ) {
1171
                return (false);
1172
            }
1173
            v_viaParameter := p_request.msgHeader.via.viaBody[1].viaParams[0];
599 tepelmann 1174
            // second element
584 garciay 1175
            if (not v_viaParameter.id == "tokenized-by") {
1176
                return (false);
1177
            }
1178
            return (true);
1179
        }
1180
 
1181
        /**
1182
         * @desc function checks indicators if topology hiding (TH) has been applied: - any element in via-header record has tokenized-by parameter
1183
         * @param Response SIP message to be analysed
1184
         * @return boolean value (true indicate TH, false otherwise)
1185
         */
600 nikolajev 1186
        function f_topologyHidingResponse(
1187
            inout Response p_response
1188
        ) runs on SipComponent
1189
        return boolean  {
584 garciay 1190
            var GenericParam v_viaParameter;
607 nikolajev 1191
            var integer i;
584 garciay 1192
 
607 nikolajev 1193
            for (i := 0; i < lengthof(p_response.msgHeader.via.viaBody); i := i + 1) {
584 garciay 1194
 
607 nikolajev 1195
                v_viaParameter := p_response.msgHeader.via.viaBody[i].viaParams[0]; // first parameter
584 garciay 1196
                if (not v_viaParameter.id == "tokenized-by") {
1197
                    return (false);
1198
                }
1199
            }
1200
            return (true);
1201
        }
1202
 
1203
 
1204
 
1205
        group SetHeaders {
1206
 
1207
 
1208
            /**
599 tepelmann 1209
             * @desc function for setting of component variables related to message header fields (message type independent: CSeq, contact, via), function uses information from userprofile
584 garciay 1210
             * @param p_cSeq_s CSeq parameter
1211
             * @param p_method method name for cSeq header field
1212
             */
599 tepelmann 1213
            function f_setHeadersGeneral(
1214
                inout CSeq p_cSeq_s,
1215
                in charstring p_method
1216
            ) runs on SipComponent  {
584 garciay 1217
                p_cSeq_s.fieldName := CSEQ_E;
1218
                p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1;
1219
                p_cSeq_s.method := p_method;
1220
                vc_cSeq := p_cSeq_s;
1221
 
1222
                vc_contact := valueof(m_Contact(m_SipUrl_contactIpaddr(vc_userprofile)));
1223
                vc_branch := c_branchCookie & f_getRndTag();
599 tepelmann 1224
                vc_via := {
1225
                    fieldName := VIA_E,
1226
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1227
                };
584 garciay 1228
            } // end function f_setHeadersGeneral
1229
 
1230
 
1231
 
1232
            /**
599 tepelmann 1233
             * @desc function for setting of component variables related to message header fields (message type independent: CSeq, contact, via), function uses information from userprofile
584 garciay 1234
             * @param p_cSeq_s CSeq parameter
1235
             * @param p_method method name for cSeq header field
1236
             */
600 nikolajev 1237
            function f_setHeadersACK(
1238
            ) runs on SipComponent  {
599 tepelmann 1239
                // vc_requestUri.hostPort := vc_reqHostPort;
584 garciay 1240
                if (vc_response.statusLine.statusCode >= 200 and vc_response.statusLine.statusCode <= 299)
599 tepelmann 1241
                // ref. RFC3261 8.1.1.7 Via
584 garciay 1242
                {
1243
                    vc_branch := c_branchCookie & f_getRndTag();
1244
                }
599 tepelmann 1245
                vc_via := {
1246
                    fieldName := VIA_E,
1247
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1248
                };
584 garciay 1249
            } // end function f_setHeadersGeneral
1250
 
1251
            /**
1252
             * @desc setting of general and basic Bye header fields in additon to the addresses (To, From, ReqUri)
1253
             * @param p_cSeq_s
1254
             */
600 nikolajev 1255
            function f_setHeadersBYE(
1256
                inout CSeq p_cSeq_s
1257
            ) runs on SipComponent  {
599 tepelmann 1258
                f_setHeadersGeneral(p_cSeq_s, "BYE"); // cseq, contact, branch, via
1259
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1260
                f_addTagInTo(vc_to);
1261
 
1262
                vc_cancel_To := vc_to;
1263
                vc_caller_To := vc_to;
1264
 
1265
                vc_caller_From := vc_from;
1266
 
1267
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1268
            } // end function f_setHeadersBYE
1269
 
1270
            /**
1271
             * @desc setting of general and basic CANCEL header fields
1272
             * @param p_cSeq_s
1273
             */
600 nikolajev 1274
            function f_setHeadersCANCEL(
1275
                inout CSeq p_cSeq_s
1276
            ) runs on SipComponent  {
584 garciay 1277
 
1278
                p_cSeq_s.method := "CANCEL";
599 tepelmann 1279
                //      vc_branch := c_branchCookie & f_getRndTag(); // STF 406: CANCEL and ACK should have the same branch as the INVITE
1280
                vc_via := {
1281
                    fieldName := VIA_E,
1282
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1283
                };
584 garciay 1284
            } // end function f_setHeadersCANCEL
1285
 
1286
            /**
1287
             * @desc function sets header field for the next outgoing REGISTER message
1288
             * @param p_cSeq_s CSeq parameter to be applied
590 garciay 1289
             * @param p_emergency Set to true in case of emergency
584 garciay 1290
             */
599 tepelmann 1291
            function f_setHeaders_REGISTER(
1292
                inout CSeq p_cSeq_s,
1293
                boolean p_emergency := false
1294
            ) runs on SipComponent  {
584 garciay 1295
                var SemicolonParam_List v_params;
1296
 
599 tepelmann 1297
                f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via
584 garciay 1298
                vc_requestUri := {
1299
                    scheme := c_sipScheme,
599 tepelmann 1300
                    components := {
1301
                        sip := {
1302
                            userInfo := omit,
1303
                            hostPort := {
1304
                                host := vc_userprofile.registrarDomain,
1305
                                portField := omit
1306
                            }
1307
                        }
1308
                    },
584 garciay 1309
                    urlParameters := omit,
1310
                    headers := omit
505 rennoch 1311
                };
584 garciay 1312
 
1313
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1314
 
599 tepelmann 1315
                vc_callId := {
1316
                    fieldName := CALL_ID_E,
607 nikolajev 1317
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1318
                };
1319
                vc_callIdReg := vc_callId; // remember callId for de-registration
584 garciay 1320
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
1321
                vc_cancel_To := vc_to;
599 tepelmann 1322
                v_params := {
1323
                    {
1324
                        id := c_tagId,
1325
                        paramValue := f_getRndTag()
1326
                    }
1327
                };
1328
                vc_from := {
1329
                    fieldName := FROM_E,
1330
                    addressField := vc_to.addressField,
1331
                    fromParams := v_params
1332
                };
584 garciay 1333
 
1334
                if (not vc_firstREGISTER_sent) {
590 garciay 1335
                    if (p_emergency) {
599 tepelmann 1336
                        v_params := {
1337
                            {
1338
                                "sos",
1339
                                omit
1340
                            }
1341
                        };
590 garciay 1342
                        vc_contact.contactBody.contactAddresses[0].addressField.addrSpecUnion.urlParameters := v_params;
599 tepelmann 1343
                    }
1344
                    else {
1345
                        v_params := {
1346
                            {
1347
                                id := c_expiresId,
1348
                                paramValue := c_shortRegistration
1349
                            }
1350
                        };
590 garciay 1351
                        vc_contact.contactBody.contactAddresses[0].contactParams := v_params;
1352
                    }
584 garciay 1353
                }
1354
 
599 tepelmann 1355
                vc_firstREGISTER_sent := true; // f_setHeaders_Register is called in deREGISTER function
1356
                vc_authorization := {
1357
                    fieldName := AUTHORIZATION_E,
1358
                    body := {f_calculatecCredentials_empty(vc_userprofile)}
1359
                };
584 garciay 1360
 
1361
                vc_via_REG := vc_via;
1362
            } // end function setHeaders_REGISTER
1363
 
1364
            /**
1365
             * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER
1366
             * @verdict
1367
             */
600 nikolajev 1368
            function f_setHeaders_2ndREGISTER(
1369
                inout CSeq p_cSeq_s
1370
            ) runs on SipComponent  {
584 garciay 1371
                var CommaParam_List v_challenge;
1372
 
599 tepelmann 1373
                // Increment CSeq sequence number
584 garciay 1374
                p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1;
1375
                vc_cSeq := p_cSeq_s;
1376
 
1377
                vc_requestUri := {
1378
                    scheme := c_sipScheme,
599 tepelmann 1379
                    components := {
1380
                        sip := {
1381
                            userInfo := omit,
1382
                            hostPort := {
1383
                                host := vc_userprofile.registrarDomain,
1384
                                portField := omit
1385
                            }
1386
                        }
1387
                    },
584 garciay 1388
                    urlParameters := omit,
1389
                    headers := omit
1390
                };
1391
 
599 tepelmann 1392
                // new branch tag due to different branch tag in new REGISTER method
584 garciay 1393
                vc_branch := c_branchCookie & f_getRndTag();
1394
 
599 tepelmann 1395
                vc_via_REG := {
1396
                    fieldName := VIA_E,
1397
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1398
                };
584 garciay 1399
 
599 tepelmann 1400
                // Extract challenge and calculate credentials for a response.
584 garciay 1401
                v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln;
1402
 
1403
 
599 tepelmann 1404
                // Prepair right answer
1405
                vc_authorization := {
1406
                    fieldName := AUTHORIZATION_E,
1407
                    body := {f_calculatecCredentials(vc_userprofile, "REGISTER", v_challenge)}
1408
                };
584 garciay 1409
            } // end function f_setHeaders_2ndREGISTER
1410
 
1411
            /**
599 tepelmann 1412
             * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER NO response in Authorization header to cause an error
584 garciay 1413
             * @verdict
1414
             */
600 nikolajev 1415
            function f_setHeaders_2ndREGISTER_wo_response(
1416
            ) runs on SipComponent  {
584 garciay 1417
                var CommaParam_List v_challenge;
1418
 
1419
                vc_branch := c_branchCookie & f_getRndTag();
1420
 
599 tepelmann 1421
                vc_via_REG := {
1422
                    fieldName := VIA_E,
1423
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1424
                };
584 garciay 1425
 
1426
                if (ischosen(vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge))
599 tepelmann 1427
                // Extract challenge and calculate credentials for a response.
584 garciay 1428
                {
1429
                    v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
599 tepelmann 1430
                }
1431
                else {
584 garciay 1432
                    v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln;
1433
                }
1434
 
599 tepelmann 1435
                // Increment CSeq sequence number
584 garciay 1436
                vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
1437
 
599 tepelmann 1438
                // Prepair right answer
1439
                vc_authorization := {
1440
                    fieldName := AUTHORIZATION_E,
1441
                    body := {f_calculatecCredentials_wo_response(vc_userprofile, "REGISTER", v_challenge)}
1442
                };
584 garciay 1443
            } // end function f_setHeaders_2ndREGISTER_wo_response
1444
 
1445
            /**
1446
             * @desc function sets via, cseq and authorization header with different private name for the next outgoing (protected) REGISTER
1447
             * @verdict
1448
             */
600 nikolajev 1449
            function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName(
1450
            ) runs on SipComponent  {
584 garciay 1451
                var CommaParam_List v_challenge;
1452
 
1453
                vc_branch := c_branchCookie & f_getRndTag();
1454
 
1455
                vc_requestUri := {
1456
                    scheme := c_sipScheme,
599 tepelmann 1457
                    components := {
1458
                        sip := {
1459
                            userInfo := omit,
1460
                            hostPort := {
1461
                                host := vc_userprofile.registrarDomain,
1462
                                portField := omit
1463
                            }
1464
                        }
1465
                    },
584 garciay 1466
                    urlParameters := omit,
1467
                    headers := omit
1468
                };
1469
 
599 tepelmann 1470
                vc_via_REG := {
1471
                    fieldName := VIA_E,
1472
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1473
                };
584 garciay 1474
 
599 tepelmann 1475
                // Extract challenge and calculate credentials for a response.
584 garciay 1476
                v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
1477
 
599 tepelmann 1478
                // Increment CSeq sequence number
584 garciay 1479
                vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
1480
 
599 tepelmann 1481
                // Prepair right answer
1482
                vc_authorization := {
1483
                    fieldName := AUTHORIZATION_E,
1484
                    body := {f_calculatecCredentialsAndChangeUserName(vc_userprofile, "REGISTER", v_challenge)}
1485
                };
584 garciay 1486
            } // end function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName
1487
 
1488
 
1489
            /**
1490
             * @desc function sets header fields for the next outgoing REGISTER (de-registration)
1491
             * @param p_cSeq_s cSeq to be used
1492
             * @verdict
1493
             */
600 nikolajev 1494
            function f_setHeaders_deREGISTER(
1495
                inout CSeq p_cSeq_s
1496
            ) runs on SipComponent  {
584 garciay 1497
                var SemicolonParam_List v_params;
1498
 
599 tepelmann 1499
                f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via
1500
                // TODO STF471 change: to be checked!!! Related to increase nonce count
1501
                // reset authorization header to not use nonce from registration (otherwise we have to increase nc)
1502
                vc_authorization := {
1503
                    fieldName := AUTHORIZATION_E,
1504
                    body := {f_calculatecCredentials_empty(vc_userprofile)}
1505
                };
584 garciay 1506
                vc_requestUri := {
1507
                    scheme := c_sipScheme,
599 tepelmann 1508
                    components := {
1509
                        sip := {
1510
                            userInfo := omit,
1511
                            hostPort := {
1512
                                host := vc_userprofile.registrarDomain,
1513
                                portField := omit
1514
                            }
1515
                        }
1516
                    },
584 garciay 1517
                    urlParameters := omit,
1518
                    headers := omit
1519
                };
1520
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
599 tepelmann 1521
                v_params := {
1522
                    {
1523
                        id := c_tagId,
1524
                        paramValue := f_getRndTag()
1525
                    }
1526
                };
1527
                vc_from := {
1528
                    fieldName := FROM_E,
1529
                    addressField := vc_to.addressField,
1530
                    fromParams := v_params
1531
                };
584 garciay 1532
 
599 tepelmann 1533
                vc_contact := {
1534
                    fieldName := CONTACT_E,
1535
                    contactBody := {wildcard := "*"}
1536
                };
584 garciay 1537
            } // end function f_setHeaders_deREGISTER
1538
 
1539
 
1540
            /**
1541
             * @desc setting of general and basic Invite header fields in additon to the addresses (To, From, ReqUri)
1542
             * @param p_cSeq_s
1543
             */
600 nikolajev 1544
            function f_setHeadersINVITE(
1545
                inout CSeq p_cSeq_s
1546
            ) runs on SipComponent  {
599 tepelmann 1547
                f_setHeadersGeneral(p_cSeq_s, "INVITE"); // cseq, contact, branch, via
1548
                vc_callId := {
1549
                    fieldName := CALL_ID_E,
607 nikolajev 1550
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1551
                };
584 garciay 1552
 
1553
                vc_cancel_To := vc_to;
1554
                vc_caller_To := vc_to;
1555
 
1556
                vc_caller_From := vc_from;
1557
 
599 tepelmann 1558
                if (ischosen(vc_requestUri.components.sip)) {
1559
                    // sip/sips call
590 garciay 1560
                    vc_reqHostPort := vc_requestUri.components.sip.hostPort;
599 tepelmann 1561
                }
1562
                else if (ischosen(vc_requestUri.components.urn)) {
1563
                    // Emergency call
590 garciay 1564
                    vc_reqUrnUri := vc_requestUri.components.urn;
599 tepelmann 1565
                }
1566
                else {
608 nikolajev 1567
                    log("*** " & __SCOPE__ &": INFO:f_setHeadersINVITE: unsupported field: ", vc_requestUri," ***");
590 garciay 1568
                    setverdict(fail);
1569
                }
592 tepelmann 1570
            }
584 garciay 1571
 
1572
            /**
1573
             * @desc setting of general and basic Update header fields in additon to the addresses (To, From, ReqUri)
1574
             * @param p_cSeq_s
1575
             */
600 nikolajev 1576
            function f_setHeadersUPDATE(
1577
                inout CSeq p_cSeq_s
1578
            ) runs on SipComponent  {
599 tepelmann 1579
                f_setHeadersGeneral(p_cSeq_s, "UPDATE"); // cseq, contact, branch, via
1580
                vc_callId := {
1581
                    fieldName := CALL_ID_E,
607 nikolajev 1582
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1583
                };
584 garciay 1584
 
1585
                vc_cancel_To := vc_to;
1586
                vc_caller_To := vc_to;
1587
 
1588
                vc_caller_From := vc_from;
1589
 
1590
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1591
            } // end function f_setHeadersUPDATE
1592
 
1593
            /**
1594
             * @desc setting of general and basic Message header fields in additon to the addresses (To, From, ReqUri)
1595
             * @param p_cSeq_s
1596
             */
600 nikolajev 1597
            function f_setHeadersMESSAGE(
1598
                inout CSeq p_cSeq_s
1599
            ) runs on SipComponent  {
599 tepelmann 1600
                f_setHeadersGeneral(p_cSeq_s, "MESSAGE"); // cseq, contact, branch, via
1601
                vc_callId := {
1602
                    fieldName := CALL_ID_E,
607 nikolajev 1603
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1604
                };
584 garciay 1605
 
1606
                vc_cancel_To := vc_to;
1607
                vc_caller_To := vc_to;
1608
 
1609
                vc_caller_From := vc_from;
1610
 
1611
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1612
            } // end function f_setHeadersMESSAGE
1613
 
1614
            /**
1615
             * @desc setting of general and basic Notify header fields in additon to the addresses (To, From, ReqUri)
1616
             * @param p_cSeq_s
1617
             */
600 nikolajev 1618
            function f_setHeadersNOTIFY(
1619
                inout CSeq p_cSeq_s
1620
            ) runs on SipComponent  {
599 tepelmann 1621
                f_setHeadersGeneral(p_cSeq_s, "NOTIFY"); // cseq, contact, branch, via
584 garciay 1622
                vc_cancel_To := vc_to;
1623
                vc_caller_To := vc_to;
1624
                vc_caller_From := vc_from;
1625
 
1626
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1627
            } // end function f_setHeadersNOTIFY
1628
 
1629
            /**
1630
             * @desc setting of general and basic Publish header fields in additon to the addresses (To, From, ReqUri)
1631
             * @param p_cSeq_s
1632
             */
600 nikolajev 1633
            function f_setHeadersPUBLISH(
1634
                inout CSeq p_cSeq_s
1635
            ) runs on SipComponent  {
599 tepelmann 1636
                f_setHeadersGeneral(p_cSeq_s, "PUBLISH"); // cseq, contact, branch, via
584 garciay 1637
                // after SUBSCRIBE message callid shall be same
599 tepelmann 1638
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1639
                vc_cancel_To := vc_to;
1640
                vc_caller_To := vc_to;
1641
 
1642
                vc_caller_From := vc_from;
1643
 
1644
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1645
            } // end function f_setHeadersPUBLISH
1646
 
1647
            /**
1648
             * @desc function sets header field for the next outgoing SUBSCRIBE message
1649
             * @param p_cSeq_s CSeq parameter to be applied
1650
             */
600 nikolajev 1651
            function f_setHeaders_SUBSCRIBE(
1652
                inout CSeq p_cSeq_s
1653
            ) runs on SipComponent  {
584 garciay 1654
                var SemicolonParam_List v_params;
1655
 
599 tepelmann 1656
                f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via
584 garciay 1657
                vc_requestUri := valueof(m_SipUrl_currDomain(vc_userprofile));
1658
 
1659
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1660
 
599 tepelmann 1661
                vc_callId := {
1662
                    fieldName := CALL_ID_E,
607 nikolajev 1663
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1664
                };
584 garciay 1665
 
599 tepelmann 1666
                // TODO STF471 change
1667
                // store callId from Subscribe message
584 garciay 1668
                vc_callIdSub := vc_callId;
1669
 
1670
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
1671
                vc_cancel_To := vc_to;
599 tepelmann 1672
                v_params := {
1673
                    {
1674
                        id := c_tagId,
1675
                        paramValue := f_getRndTag()
1676
                    }
1677
                };
1678
                vc_from := {
1679
                    fieldName := FROM_E,
1680
                    addressField := vc_to.addressField,
1681
                    fromParams := v_params
1682
                };
584 garciay 1683
            } // end function setHeaders_SUBSCRIBE
1684
 
1685
            /**
1686
             * @desc setting of general and basic Subscribe header fields in additon to the addresses (To, From, ReqUri)
1687
             * @param p_cSeq_s
1688
             */
600 nikolajev 1689
            function f_setHeadersSUBSCRIBE(
1690
                inout CSeq p_cSeq_s
1691
            ) runs on SipComponent  {
599 tepelmann 1692
                f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via
1693
                vc_callId := {
1694
                    fieldName := CALL_ID_E,
607 nikolajev 1695
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1696
                };
584 garciay 1697
 
1698
                vc_cancel_To := vc_to;
1699
                vc_caller_To := vc_to;
1700
 
1701
                vc_caller_From := vc_from;
1702
 
1703
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1704
            } // end function f_setHeadersMESSAGE
1705
 
1706
            /**
1707
             * @desc setting of general and basic REFER header fields in additon to the addresses (To, From, ReqUri)
1708
             * @param p_cSeq_s
1709
             */
600 nikolajev 1710
            function f_setHeadersREFER(
1711
                inout CSeq p_cSeq_s
1712
            ) runs on SipComponent  {
599 tepelmann 1713
                f_setHeadersGeneral(p_cSeq_s, "REFER"); // cseq, contact, branch, via
1714
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1715
                vc_cancel_To := vc_to;
1716
                vc_caller_To := vc_to;
1717
 
1718
                vc_caller_From := vc_from;
1719
 
1720
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1721
            } // end function f_setHeadersREFER
1722
 
1723
            /**
1724
             * @desc This function reads all necessary headers from the received REGISTER message and generate the tag for the answer
1725
             * @param p_Request REGISTER that has been received
1726
             */
600 nikolajev 1727
            function f_setHeadersOnReceiptOfREGISTER(
1728
                Request p_Request
1729
            ) runs on SipComponent  {
584 garciay 1730
 
1731
                f_setHeadersOnReceiptOfRequest(p_Request);
1732
 
1733
                vc_callId := p_Request.msgHeader.callId;
1734
                vc_caller_From := vc_from;
1735
                f_addTagInTo(vc_to);
1736
                vc_caller_To := vc_to;
1737
                vc_requestUri := p_Request.requestLine.requestUri;
1738
 
1739
                vc_cancel_To := p_Request.msgHeader.toField;
1740
 
1741
                if (isvalue(p_Request.msgHeader.contact) and (not ischosen(p_Request.msgHeader.contact.contactBody.wildcard))) {
1742
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1743
                }
1744
 
599 tepelmann 1745
                // update callee information and pick up tag if the call need to be canceled
1746
                vc_callee_To := {
1747
                    fieldName := TO_E,
1748
                    addressField := vc_caller_From.addressField,
1749
                    toParams := vc_caller_From.fromParams
1750
                };
584 garciay 1751
 
599 tepelmann 1752
                vc_callee_From := {
1753
                    fieldName := FROM_E,
1754
                    addressField := vc_caller_To.addressField,
1755
                    fromParams := vc_caller_To.toParams
1756
                };
584 garciay 1757
 
1758
                if (isvalue(p_Request.msgHeader.authorization)) {
598 tepelmann 1759
                    vc_authorization := valueof(p_Request.msgHeader.authorization);
584 garciay 1760
                }
1761
            } // end f_setHeadersOnReceiptOfREGISTER
1762
 
1763
            /**
1764
             * @desc This function reads all necessary headers from the received SUBSCRIBE message and generate the tag for the answer
1765
             * @param p_Request SUBSCRIBE that has been received
1766
             */
600 nikolajev 1767
            function f_setHeadersOnReceiptOfSUBSCRIBE(
1768
                Request p_Request
1769
            ) runs on SipComponent  {
584 garciay 1770
 
1771
                f_setHeadersOnReceiptOfRequest(p_Request);
1772
 
1773
                vc_callId := p_Request.msgHeader.callId;
1774
                vc_caller_From := vc_from;
1775
                f_addTagInTo(vc_to);
1776
                vc_caller_To := vc_to;
1777
                vc_requestUri := p_Request.requestLine.requestUri;
1778
 
1779
                vc_cancel_To := p_Request.msgHeader.toField;
1780
 
1781
                if (isvalue(p_Request.msgHeader.contact)) {
1782
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1783
                }
1784
 
599 tepelmann 1785
                // update callee information and pick up tag if the call need to be canceled
1786
                vc_callee_To := {
1787
                    fieldName := TO_E,
1788
                    addressField := vc_caller_From.addressField,
1789
                    toParams := vc_caller_From.fromParams
1790
                };
584 garciay 1791
 
599 tepelmann 1792
                vc_callee_From := {
1793
                    fieldName := FROM_E,
1794
                    addressField := vc_caller_To.addressField,
1795
                    fromParams := vc_caller_To.toParams
1796
                };
584 garciay 1797
            } // end f_setHeadersOnReceiptOfSUBSCRIBE
1798
 
600 nikolajev 1799
            function f_setHeadersOnReceiptOfREFER(
1800
                Request p_Request
1801
            ) runs on SipComponent  {
584 garciay 1802
 
1803
                f_setHeadersOnReceiptOfRequest(p_Request);
1804
 
1805
                vc_requestUri := p_Request.requestLine.requestUri;
1806
                vc_cancel_To := p_Request.msgHeader.toField;
1807
 
1808
                if (isvalue(p_Request.msgHeader.contact)) {
1809
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1810
                    vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1811
                }
1812
 
599 tepelmann 1813
                // update callee information and pick up tag if the call need to be canceled
1814
                vc_callee_To := {
1815
                    fieldName := TO_E,
1816
                    addressField := vc_caller_From.addressField,
1817
                    toParams := vc_caller_From.fromParams
1818
                };
584 garciay 1819
 
599 tepelmann 1820
                vc_callee_From := {
1821
                    fieldName := FROM_E,
1822
                    addressField := vc_caller_To.addressField,
1823
                    fromParams := vc_caller_To.toParams
1824
                };
584 garciay 1825
            } // end f_setHeadersOnReceiptOfREFER
1826
 
1827
            /**
1828
             * @desc function reads all necessary headers from the received INVITE message and generate the tag for the answer
1829
             * @param p_Request received INVITE message
1830
             * @verdict
1831
             */
600 nikolajev 1832
            function f_setHeadersOnReceiptOfINVITE(
1833
                Request p_Request
1834
            ) runs on SipComponent  {
607 nikolajev 1835
                var integer i, j;
1836
                var integer v_length;
1837
 
584 garciay 1838
                f_setHeadersOnReceiptOfRequest(p_Request);
1839
 
1840
                vc_callId := p_Request.msgHeader.callId;
1841
 
1842
                vc_requestUri2 := p_Request.requestLine.requestUri;
1843
 
1844
                vc_cancel_To := p_Request.msgHeader.toField;
1845
                f_addTagInTo(vc_to);
1846
                vc_caller_From := vc_from;
1847
                vc_caller_To := vc_to;
1848
 
1849
                if (isvalue(p_Request.msgHeader.contact)) {
1850
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1851
                    vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1852
                }
1853
 
599 tepelmann 1854
                // update callee information and pick up tag if the call need to be canceled
1855
                vc_callee_To := {
1856
                    fieldName := TO_E,
1857
                    addressField := vc_caller_From.addressField,
1858
                    toParams := vc_caller_From.fromParams
1859
                };
584 garciay 1860
 
599 tepelmann 1861
                vc_callee_From := {
1862
                    fieldName := FROM_E,
1863
                    addressField := vc_caller_To.addressField,
1864
                    fromParams := vc_caller_To.toParams
1865
                };
584 garciay 1866
 
1867
                if (isvalue(p_Request.msgHeader.privacy)) {
1868
                    vc_privacy := p_Request.msgHeader.privacy;
1869
                }
1870
 
1871
                if (isvalue(p_Request.messageBody)) {
599 tepelmann 1872
                    // cleaning of attributes before assignment
584 garciay 1873
                    if (isvalue(vc_sdp_remote.media_list)) {
607 nikolajev 1874
                        v_length := lengthof(vc_sdp_remote.media_list);
1875
                        for (i := 0; i < v_length; i := i + 1) {
584 garciay 1876
                            if (isvalue(vc_sdp_remote.media_list[i].attributes)) {
1877
                                vc_sdp_remote.media_list[i].attributes := omit;
1878
                            }
1879
                        }
1880
                    }
1881
 
599 tepelmann 1882
                    // save SDP if present
584 garciay 1883
                    if (ischosen(p_Request.messageBody.sdpMessageBody)) {
1884
                        vc_sdp_remote := p_Request.messageBody.sdpMessageBody;
1885
                        vc_sdp_remote_is_valid := true;
1886
                        f_prepare_SDP_answer();
1887
                    }
1888
 
599 tepelmann 1889
                    // save XML if present
584 garciay 1890
                    if (ischosen(p_Request.messageBody.xmlBody)) {
1891
                        vc_xml_remote := p_Request.messageBody.xmlBody;
1892
                    }
1893
 
1894
                    if (ischosen(p_Request.messageBody.mimeMessageBody)) {
1895
 
607 nikolajev 1896
                        for (j := 0; j < lengthof(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) {
584 garciay 1897
                            if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) {
1898
                                vc_sdp_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
1899
                                vc_sdp_remote_is_valid := true;
1900
                                f_prepare_SDP_answer();
1901
                            }
1902
                            if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) {
1903
                                vc_xml_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
1904
                            }
1905
                        }
1906
                    }
1907
                }
1908
 
1909
                if (isvalue(p_Request.msgHeader.supported.optionsTags)) {
607 nikolajev 1910
                    for (i := lengthof(p_Request.msgHeader.supported.optionsTags); i > 0; i := i - 1) {
584 garciay 1911
                        if (p_Request.msgHeader.supported.optionsTags[i - 1] == "100rel") {
1912
                            vc_supported_100rel := true;
1913
                        }
1914
                        if (p_Request.msgHeader.supported.optionsTags[i - 1] == "precondition") {
1915
                            vc_supported_precondition := true;
1916
                        }
1917
                    }
1918
                }
1919
            } // end f_setHeadersOnReceiptOfINVITE
1920
 
1921
            /**
1922
             * @desc function reads header field of a received BYE message
1923
             * @param p_Request received BYE
1924
             */
600 nikolajev 1925
            function f_setHeadersOnReceiptOfBYE(
1926
                Request p_BYE_Request
1927
            ) runs on SipComponent  {
584 garciay 1928
 
1929
                f_setHeadersOnReceiptOfRequest(p_BYE_Request);
1930
                vc_callId := p_BYE_Request.msgHeader.callId;
1931
            } // end f_setHeadersOnReceiptOfBYE
1932
 
1933
            /**
1934
             * @desc function reads header field from an incoming Request message
1935
             * @param p_Request received Request message
1936
             */
600 nikolajev 1937
            function f_setHeadersOnReceiptOfRequest(
1938
                Request p_Request
1939
            ) runs on SipComponent  {
584 garciay 1940
                vc_request := p_Request;
1941
                vc_callId := p_Request.msgHeader.callId;
599 tepelmann 1942
                vc_cSeq := valueof(p_Request.msgHeader.cSeq); // CSeq is mandatory
584 garciay 1943
                vc_iut_CSeq := p_Request.msgHeader.cSeq;
1944
                vc_from := p_Request.msgHeader.fromField;
1945
                vc_caller_From := p_Request.msgHeader.fromField;
1946
                vc_to := p_Request.msgHeader.toField;
1947
                vc_caller_To := p_Request.msgHeader.toField;
1948
                vc_via := p_Request.msgHeader.via;
599 tepelmann 1949
                // update sent_label according to received via header field
584 garciay 1950
                f_getViaReplyAddr(vc_via.viaBody, vc_sent_label);
1951
 
599 tepelmann 1952
                // Catch route
584 garciay 1953
                vc_boo_recordRoute := false;
1954
 
1955
                // add tag field into To header if tag is not present
1956
                if (not (isvalue(p_Request.msgHeader.toField.toParams))) {
599 tepelmann 1957
                    vc_to.toParams := {
1958
                        {
1959
                            id := c_tagId,
1960
                            paramValue := f_getRndTag()
1961
                        }
1962
                    };
584 garciay 1963
                    vc_caller_To := vc_to;
1964
                }
1965
                if (isvalue(p_Request.msgHeader.recordRoute)) {
1966
                    vc_boo_recordRoute := true;
1967
                    vc_recordRoute := p_Request.msgHeader.recordRoute;
1968
                }
1969
            } // end f_setHeadersOnReceiptOfRequest
1970
 
1971
            /**
1972
             * @desc functions reads header fields from an incoming Response message
1973
             * @param p_cSeq
1974
             * @param p_response received response message
1975
             * @verdict
1976
             */
599 tepelmann 1977
            function f_setHeadersOnReceiptOfResponse(
1978
                Response p_response
1979
            ) runs on SipComponent  {
607 nikolajev 1980
                var integer i, j, v_nbroute;
584 garciay 1981
                var template(omit) Contact v_contact;
599 tepelmann 1982
                // only for local purpose
584 garciay 1983
                vc_response := p_response;
599 tepelmann 1984
                // vc_cSeq := p_cSeq; //must not save global c_seq because it can overwrite temporary cSeq
584 garciay 1985
                vc_to := p_response.msgHeader.toField;
1986
                vc_from := p_response.msgHeader.fromField;
1987
                vc_caller_To := vc_to;
1988
                vc_caller_From := vc_from;
1989
 
1990
                if (isvalue(p_response.msgHeader.contact)) {
1991
                    v_contact := p_response.msgHeader.contact;
1992
                    if (ischosen(v_contact.contactBody.contactAddresses)) {
1993
                        vc_reqHostPort := f_getContactAddr(valueof(v_contact.contactBody.contactAddresses[0]));
1994
                        vc_requestUri := f_getContactUri(valueof(v_contact.contactBody.contactAddresses[0]));
1995
                    }
599 tepelmann 1996
                }
1997
                else {
1998
                    if (ischosen(vc_to.addressField.addrSpecUnion.components.sip)) {
1999
                        // sip/sips call
2000
                        vc_reqHostPort := vc_to.addressField.addrSpecUnion.components.sip.hostPort;
584 garciay 2001
                    }
599 tepelmann 2002
                    else if (ischosen(vc_to.addressField.addrSpecUnion.components.urn)) {
2003
                        // Emergency call
2004
                        vc_reqUrnUri := vc_to.addressField.addrSpecUnion.components.urn;
2005
                    }
2006
                    else {
607 nikolajev 2007
                        log("*** f_setHeadersOnReceiptOfResponse: INFO: unsupported field: ", vc_to, " ***");
599 tepelmann 2008
                        setverdict(fail);
2009
                    }
2010
                    vc_requestUri := vc_to.addressField.addrSpecUnion;
584 garciay 2011
                }
2012
 
599 tepelmann 2013
                vc_callee_To := {
2014
                    fieldName := TO_E,
2015
                    addressField := vc_caller_From.addressField,
2016
                    toParams := vc_caller_From.fromParams
2017
                };
584 garciay 2018
 
599 tepelmann 2019
                vc_callee_From := {
2020
                    fieldName := FROM_E,
2021
                    addressField := vc_caller_To.addressField,
2022
                    fromParams := vc_caller_To.toParams
2023
                };
584 garciay 2024
 
2025
                vc_via := p_response.msgHeader.via;
2026
 
599 tepelmann 2027
                // Route Management
584 garciay 2028
                if (isvalue(p_response.msgHeader.recordRoute)) {
2029
                    vc_recordRoute := p_response.msgHeader.recordRoute;
2030
                    v_nbroute := lengthof(vc_recordRoute.routeBody);
599 tepelmann 2031
                    // copy and reverse the order of the routes in route header
607 nikolajev 2032
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2033
                        j := v_nbroute - 1 - i;
2034
                        vc_route.routeBody[j] := vc_recordRoute.routeBody[i];
584 garciay 2035
                    }
2036
                    vc_route.fieldName := ROUTE_E;
2037
                    vc_boo_recordRoute := true;
2038
                    vc_boo_route := true;
599 tepelmann 2039
                }
2040
                else {
584 garciay 2041
                    vc_boo_recordRoute := false;
2042
                    vc_boo_route := false;
2043
                }
2044
 
2045
 
599 tepelmann 2046
                // extentions due to new fields in PRACK and UPDATE messages
584 garciay 2047
                if (isvalue(p_response.msgHeader.rSeq)) {
2048
                    vc_rAck := {
2049
                        fieldName := RACK_E,
2050
                        responseNum := valueof(p_response.msgHeader.rSeq).responseNum,
2051
                        seqNumber := valueof(p_response.msgHeader.cSeq).seqNumber,
2052
                        method := valueof(p_response.msgHeader.cSeq).method
2053
                    };
2054
                }
2055
 
599 tepelmann 2056
                // extentions due to new HistoryInfo fields 180 or 200OK messages
584 garciay 2057
                if (isvalue(p_response.msgHeader.historyInfo)) {
2058
                    vc_historyInfoList := valueof(p_response.msgHeader.historyInfo).historyInfoList;
2059
                    vc_history_is_valid := true;
599 tepelmann 2060
                }
2061
                else {
584 garciay 2062
                    vc_history_is_valid := false;
2063
                }
2064
 
599 tepelmann 2065
                // sdpMessageBody answer
584 garciay 2066
                if (isvalue(p_response.messageBody)) {
2067
                    if (ischosen(p_response.messageBody.sdpMessageBody)) {
2068
                        vc_sdp_remote := p_response.messageBody.sdpMessageBody;
2069
                        vc_sdp_remote_is_valid := true;
2070
                    }
2071
 
2072
                    if (ischosen(p_response.messageBody.xmlBody)) {
2073
                        vc_xml_remote := p_response.messageBody.xmlBody;
2074
                    }
2075
 
2076
                    if (ischosen(p_response.messageBody.mimeMessageBody)) {
2077
 
607 nikolajev 2078
                        for (j := 0; j < lengthof(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) {
584 garciay 2079
                            if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) {
2080
                                vc_sdp_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
2081
                            }
2082
                            if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) {
2083
                                vc_xml_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
2084
                            }
2085
                        }
2086
                    }
2087
                }
2088
            } // end function f_setHeadersOnReceiptOfResponse
2089
 
2090
            /**
2091
             * @desc functions reads ServiceRoute header field from an incoming 200 Response message in registration
2092
             * @param p_cSeq
2093
             * @param p_response received response message
2094
             */
599 tepelmann 2095
            function f_getServiceRouteMapIntoRouteInRegistration(
2096
                Response p_response
2097
            ) runs on SipComponent  {
607 nikolajev 2098
                var integer i, j, v_nbroute;
584 garciay 2099
                var template(omit) ServiceRoute v_serviceRoute;
2100
 
599 tepelmann 2101
                // Route Management
584 garciay 2102
                if (isvalue(p_response.msgHeader.serviceRoute)) {
2103
                    v_serviceRoute := p_response.msgHeader.serviceRoute;
2104
                    v_nbroute := lengthof(v_serviceRoute.routeBody);
599 tepelmann 2105
                    // copy and reverse the order of the routes in route header
607 nikolajev 2106
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2107
                        j := v_nbroute - 1 - i;
2108
                        vc_route.routeBody[j] := v_serviceRoute.routeBody[i];
584 garciay 2109
                    }
2110
                    vc_route.fieldName := ROUTE_E;
2111
                    vc_route_REG := vc_route;
2112
                    vc_boo_route := true;
2113
                }
2114
            } // end function f_getServiceRouteMapIntoRouteInRegistration
2115
 
2116
            /**
2117
             * @desc functions reads Route header field from an incoming Request message and generate RecordRoute
2118
             * @param p_cSeq
2119
             * @param p_request received request message
2120
             */
599 tepelmann 2121
            function f_getRouteMapIntoRecordRoute(
2122
                Request p_request
2123
            ) runs on SipComponent  {
607 nikolajev 2124
                var integer i, j, v_nbroute;
584 garciay 2125
                var template(omit) Route v_route;
2126
 
599 tepelmann 2127
                // Route Management
584 garciay 2128
                if (isvalue(p_request.msgHeader.route)) {
2129
                    v_route := p_request.msgHeader.route;
2130
                    v_nbroute := lengthof(v_route.routeBody);
599 tepelmann 2131
                    // copy and reverse the order of the routes in route header
607 nikolajev 2132
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2133
                        j := v_nbroute - 1 - i;
2134
                        vc_recordRoute.routeBody[j] := v_route.routeBody[i];
584 garciay 2135
                    }
2136
                    vc_recordRoute.fieldName := RECORD_ROUTE_E;
2137
 
2138
                    vc_boo_recordRoute := true;
2139
                }
2140
            } // end function f_getRouteMapIntoRecordRoute
2141
 
599 tepelmann 2142
 
597 tepelmann 2143
        } // end group SetHeaders
2144
 
2145
 
599 tepelmann 2146
 
584 garciay 2147
    } // end group FieldOperations
2148
 
2149
    group SDPOperations {
2150
 
2151
        /**
2152
         * @desc check if message body include SDP attribute (2nd parameter) for any media
2153
         */
599 tepelmann 2154
        function f_check_attribute(
2155
            in SDP_Message p_sdp,
2156
            in template SDP_attribute p_attribute
600 nikolajev 2157
        ) runs on SipComponent
2158
        return boolean  {
607 nikolajev 2159
            var integer i, j;
584 garciay 2160
 
2161
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2162
                for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) {
584 garciay 2163
                    if (isvalue(p_sdp.media_list[j].attributes)) {
607 nikolajev 2164
                        for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) {
584 garciay 2165
                            if (match(p_sdp.media_list[j].attributes[i], p_attribute)) {
2166
                                return (true);
2167
                            }
2168
                        }
2169
                    }
2170
                }
2171
            }
2172
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2173
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2174
                    if (match(p_sdp.attributes[j], p_attribute)) {
2175
                        return (true);
2176
                    }
2177
                }
2178
            }
2179
 
2180
            return (false);
505 rennoch 2181
        }
9 rennoch 2182
 
584 garciay 2183
        /**
2184
         * @desc check if message body include SDP (session level) attribute (2nd parameter) for any media
2185
         */
599 tepelmann 2186
        function f_check_session_attribute(
2187
            in SDP_Message p_sdp,
2188
            in template SDP_attribute p_attribute
600 nikolajev 2189
        ) runs on SipComponent
2190
        return boolean  {
607 nikolajev 2191
            var integer j;
234 rennoch 2192
 
584 garciay 2193
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2194
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2195
                    if (match(p_sdp.attributes[j], p_attribute)) {
2196
                        return (true);
2197
                    }
2198
                }
2199
            }
9 rennoch 2200
 
584 garciay 2201
            return (false);
2202
        }
9 rennoch 2203
 
584 garciay 2204
        /**
2205
         * @desc identify an SDP direction attribute (session or first media attribute) in a SDP message and return its answer value
2206
         * @param p_sdp the SDP message that has been received
2207
         * @param p_attribute incoming SDP attribute that need to be used for the SDP direction (answer)
2208
         * @return the new attribute (to be send out) derived from the incoming SDP value
2209
         * @verdict
2210
         */
599 tepelmann 2211
        function f_get_attribute_answer(
2212
            in SDP_Message p_sdp,
2213
            in template SDP_attribute p_attribute
600 nikolajev 2214
        ) runs on SipComponent
2215
        return SDP_attribute  {
607 nikolajev 2216
            var integer i, j;
584 garciay 2217
            var template SDP_attribute v_attribute := p_attribute;
9 rennoch 2218
 
599 tepelmann 2219
            // check if the selected attribute is included in the SDP offer (session attributes)
584 garciay 2220
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2221
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2222
                    if (match(p_sdp.attributes[j], p_attribute)) {
2223
                        v_attribute := p_sdp.attributes[j];
2224
                    }
2225
                }
599 tepelmann 2226
            }
2227
            else
2228
            // check if the selected attribute is included in the SDP offer (any of the media attributes)
584 garciay 2229
            {
2230
                if (isvalue(p_sdp.media_list)) {
607 nikolajev 2231
                    for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) {
584 garciay 2232
                        if (isvalue(p_sdp.media_list[j].attributes)) {
607 nikolajev 2233
                            for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) {
584 garciay 2234
                                if (match(p_sdp.media_list[j].attributes[i], p_attribute)) {
2235
                                    v_attribute := p_sdp.media_list[j].attributes[i];
2236
                                }
2237
                            }
2238
                        }
2239
                    }
2240
                }
2241
            }
9 rennoch 2242
 
584 garciay 2243
            select (valueof(v_attribute)) {
2244
                case (mw_attribute_sendonly) {
2245
                    return (valueof(m_attribute_recvonly));
2246
                }
2247
                case (mw_attribute_sendrecv) {
2248
                    return (valueof(m_attribute_sendrecv));
599 tepelmann 2249
                } // MRO
584 garciay 2250
                case (mw_attribute_inactive) {
2251
                    return (valueof(m_attribute_inactive));
599 tepelmann 2252
                } // MRO
584 garciay 2253
                case (mw_attribute_recvonly) {
2254
                    return (valueof(m_attribute_sendonly));
599 tepelmann 2255
                } // MRO
584 garciay 2256
            }
599 tepelmann 2257
            return (valueof(m_attribute_sendrecv)); // the default return value in case of missing attribute offer
584 garciay 2258
        }
9 rennoch 2259
 
584 garciay 2260
        /**
2261
         * @desc check if message body include SDP bandwidth (2nd parameter) either for the session or a media description
2262
         */
599 tepelmann 2263
        function f_check_bandwidth(
607 nikolajev 2264
            in SDP_Message p_loc_sdp,
2265
            in template SDP_bandwidth p_loc_bandw
600 nikolajev 2266
        ) runs on SipComponent
2267
        return boolean  {
607 nikolajev 2268
            var integer i, j;
2269
            if (isvalue(p_loc_sdp.bandwidth)) {
2270
                for (j := 0; j < lengthof(p_loc_sdp.bandwidth); j := j + 1) {
2271
                    if (match(p_loc_sdp.bandwidth[j], p_loc_bandw)) {
584 garciay 2272
                        return (true);
2273
                    }
2274
                }
2275
            }
607 nikolajev 2276
            if (isvalue(p_loc_sdp.media_list)) {
2277
                for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) {
2278
                    if (isvalue(p_loc_sdp.media_list[j].bandwidth)) {
2279
                        for (i := 0; i < lengthof(p_loc_sdp.media_list[j].bandwidth); i := i + 1) {
2280
                            if (match(p_loc_sdp.media_list[j].bandwidth[i], p_loc_bandw)) {
584 garciay 2281
                                return (true);
2282
                            }
2283
                        }
2284
                    }
2285
                }
2286
            }
2287
 
2288
            return (false);
2289
        }
2290
 
2291
        /**
2292
         * @desc check if message body include SDP media (2nd parameter)
2293
         */
599 tepelmann 2294
        function f_check_media(
607 nikolajev 2295
            in SDP_Message p_loc_sdp,
2296
            in template(present) SDP_media_desc p_loc_media
600 nikolajev 2297
        ) runs on SipComponent
2298
        return boolean  {
607 nikolajev 2299
            var integer j;
2300
            if (isvalue(p_loc_sdp.media_list)) {
2301
                for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) {
2302
                    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)) {
584 garciay 2303
                        return (true);
2304
                    }
2305
                }
2306
            }
2307
            return (false);
2308
        }
2309
 
2310
        /**
2311
         * @desc check if message body include precondition mechanism (a=des and a=curr) retrun true, else false
2312
         * @param loc_sdp SDP message
2313
         */
600 nikolajev 2314
        function f_check_precondition(
607 nikolajev 2315
            in SDP_Message p_loc_sdp
600 nikolajev 2316
        ) runs on SipComponent
2317
        return boolean  {
607 nikolajev 2318
            if (f_check_attribute(p_loc_sdp, mw_attribute_des) or f_check_attribute(p_loc_sdp, mw_attribute_curr)) {
584 garciay 2319
                return (true);
2320
            }
2321
 
2322
            return (false);
2323
        }
2324
 
2325
 
2326
        /**
2327
         * @desc check if message body include SDP media direction return true, else false
2328
         */
600 nikolajev 2329
        function f_check_media_direction(
607 nikolajev 2330
            in SDP_Message p_loc_sdp
600 nikolajev 2331
        ) runs on SipComponent
2332
        return boolean  {
584 garciay 2333
 
607 nikolajev 2334
            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)) {
584 garciay 2335
                return (true);
2336
            }
2337
 
2338
            return (false);
2339
        }
2340
 
2341
        /**
2342
         * @desc copy media/attribute lines from remote to local SDP variable
2343
         */
599 tepelmann 2344
        function f_check_SDP(
607 nikolajev 2345
            integer p_loc_sdp,
2346
            integer p_loc_codec
600 nikolajev 2347
        ) runs on SipComponent
2348
        return boolean  {
607 nikolajev 2349
            var SDP_media_desc v_media := f_prepare_media(p_loc_sdp, p_loc_codec);
584 garciay 2350
            if (vc_sdp_remote.media_list[0].media_field.media != v_media.media_field.media) {
2351
                return false;
2352
            }
2353
            if (vc_sdp_remote.media_list[0].media_field.transport != v_media.media_field.transport) {
2354
                return false;
2355
            }
2356
            if (vc_sdp_remote.media_list[0].media_field.fmts != v_media.media_field.fmts) {
2357
                return false;
2358
            }
2359
 
2360
            return true;
2361
        }
2362
 
2363
        /**
2364
         * @desc replace the first curr media attribute with the given value.
2365
         * @param p_sdp SDP message to modify
2366
         * @param p_curr new curr attribute
2367
         */
599 tepelmann 2368
        function f_replace_curr_attribute(
2369
            inout SDP_Message p_sdp,
2370
            in SDP_attribute_curr p_curr
2371
        ) {
607 nikolajev 2372
            var integer i;
2373
            var integer v_mn;
584 garciay 2374
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2375
                v_mn := lengthof(p_sdp.media_list[0].attributes);
2376
                for (i := 0; i < v_mn; i := i + 1) {
584 garciay 2377
                    if (ischosen(p_sdp.media_list[0].attributes[i].curr)) {
2378
                        p_sdp.media_list[0].attributes[i].curr := p_curr;
607 nikolajev 2379
                        i := v_mn;
584 garciay 2380
                    }
2381
                }
2382
            }
2383
        }
2384
 
2385
        /**
2386
         * @desc append new media attribute to the first media description.
2387
         * @param p_sdp SDP message to modify
2388
         * @param p_att SDP attribute to appand
2389
         */
599 tepelmann 2390
        function f_append_media_attribute(
2391
            inout SDP_Message p_sdp,
2392
            in SDP_attribute p_att
2393
        ) {
607 nikolajev 2394
            var integer v_mn;
584 garciay 2395
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2396
                v_mn := lengthof(p_sdp.media_list[0].attributes);
2397
                p_sdp.media_list[0].attributes[v_mn] := p_att;
584 garciay 2398
            }
2399
        }
2400
 
2401
 
2402
        /**
2403
         * @desc append new media to the existing media list in SDP
2404
         */
599 tepelmann 2405
        function f_append_media(
607 nikolajev 2406
            inout SDP_Message p_loc_SDP,
2407
            template(value) SDP_media_desc p_loc_media
599 tepelmann 2408
        ) {
607 nikolajev 2409
            var integer v_mn := lengthof(p_loc_SDP.media_list);
2410
            p_loc_SDP.media_list[v_mn] := valueof(p_loc_media);
584 garciay 2411
        }
2412
 
2413
        /**
2414
         * @desc repare media/attribute lines
2415
         */
599 tepelmann 2416
        function f_prepare_media(
607 nikolajev 2417
            integer p_loc_sdp,
2418
            integer p_loc_codec
600 nikolajev 2419
        ) runs on SipComponent
2420
        return SDP_media_desc  {
599 tepelmann 2421
            var charstring v_codecs[32] := {"PCMU/8000", "GSM/8000", "G723/8000", "DVI4/8000", "DVI4/16000", "LPC/8000", "PCMA/8000", "G722/8000", "L16/44100/2", "L16/44100", "QCELP/8000", "CN/8000", "MPA/90000", "G728/8000", "DVI4/11025", "DVI4/22050", "G729/8000", "G726-40/8000", "G726-32/8000", "G726-24/8000", "G726-16/8000", "G726D/8000", "G726E/8000"