Rev

Rev 604 | 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 607 2014-02-27 17:24:26Z nikolajev $
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.";
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);
607 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);
607 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  {
584 garciay 1168
            var GenericParam v_viaParameter := p_request.msgHeader.via.viaBody[1].viaParams[0];
599 tepelmann 1169
            // second element
584 garciay 1170
            if (not v_viaParameter.id == "tokenized-by") {
1171
                return (false);
1172
            }
1173
            return (true);
1174
        }
1175
 
1176
        /**
1177
         * @desc function checks indicators if topology hiding (TH) has been applied: - any element in via-header record has tokenized-by parameter
1178
         * @param Response SIP message to be analysed
1179
         * @return boolean value (true indicate TH, false otherwise)
1180
         */
600 nikolajev 1181
        function f_topologyHidingResponse(
1182
            inout Response p_response
1183
        ) runs on SipComponent
1184
        return boolean  {
584 garciay 1185
            var GenericParam v_viaParameter;
607 nikolajev 1186
            var integer i;
584 garciay 1187
 
607 nikolajev 1188
            for (i := 0; i < lengthof(p_response.msgHeader.via.viaBody); i := i + 1) {
584 garciay 1189
 
607 nikolajev 1190
                v_viaParameter := p_response.msgHeader.via.viaBody[i].viaParams[0]; // first parameter
584 garciay 1191
                if (not v_viaParameter.id == "tokenized-by") {
1192
                    return (false);
1193
                }
1194
            }
1195
            return (true);
1196
        }
1197
 
1198
 
1199
 
1200
        group SetHeaders {
1201
 
1202
 
1203
            /**
599 tepelmann 1204
             * @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 1205
             * @param p_cSeq_s CSeq parameter
1206
             * @param p_method method name for cSeq header field
1207
             */
599 tepelmann 1208
            function f_setHeadersGeneral(
1209
                inout CSeq p_cSeq_s,
1210
                in charstring p_method
1211
            ) runs on SipComponent  {
584 garciay 1212
                p_cSeq_s.fieldName := CSEQ_E;
1213
                p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1;
1214
                p_cSeq_s.method := p_method;
1215
                vc_cSeq := p_cSeq_s;
1216
 
1217
                vc_contact := valueof(m_Contact(m_SipUrl_contactIpaddr(vc_userprofile)));
1218
                vc_branch := c_branchCookie & f_getRndTag();
599 tepelmann 1219
                vc_via := {
1220
                    fieldName := VIA_E,
1221
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1222
                };
584 garciay 1223
            } // end function f_setHeadersGeneral
1224
 
1225
 
1226
 
1227
            /**
599 tepelmann 1228
             * @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 1229
             * @param p_cSeq_s CSeq parameter
1230
             * @param p_method method name for cSeq header field
1231
             */
600 nikolajev 1232
            function f_setHeadersACK(
1233
            ) runs on SipComponent  {
599 tepelmann 1234
                // vc_requestUri.hostPort := vc_reqHostPort;
584 garciay 1235
                if (vc_response.statusLine.statusCode >= 200 and vc_response.statusLine.statusCode <= 299)
599 tepelmann 1236
                // ref. RFC3261 8.1.1.7 Via
584 garciay 1237
                {
1238
                    vc_branch := c_branchCookie & f_getRndTag();
1239
                }
599 tepelmann 1240
                vc_via := {
1241
                    fieldName := VIA_E,
1242
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1243
                };
584 garciay 1244
            } // end function f_setHeadersGeneral
1245
 
1246
            /**
1247
             * @desc setting of general and basic Bye header fields in additon to the addresses (To, From, ReqUri)
1248
             * @param p_cSeq_s
1249
             */
600 nikolajev 1250
            function f_setHeadersBYE(
1251
                inout CSeq p_cSeq_s
1252
            ) runs on SipComponent  {
599 tepelmann 1253
                f_setHeadersGeneral(p_cSeq_s, "BYE"); // cseq, contact, branch, via
1254
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1255
                f_addTagInTo(vc_to);
1256
 
1257
                vc_cancel_To := vc_to;
1258
                vc_caller_To := vc_to;
1259
 
1260
                vc_caller_From := vc_from;
1261
 
1262
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1263
            } // end function f_setHeadersBYE
1264
 
1265
            /**
1266
             * @desc setting of general and basic CANCEL header fields
1267
             * @param p_cSeq_s
1268
             */
600 nikolajev 1269
            function f_setHeadersCANCEL(
1270
                inout CSeq p_cSeq_s
1271
            ) runs on SipComponent  {
584 garciay 1272
 
1273
                p_cSeq_s.method := "CANCEL";
599 tepelmann 1274
                //      vc_branch := c_branchCookie & f_getRndTag(); // STF 406: CANCEL and ACK should have the same branch as the INVITE
1275
                vc_via := {
1276
                    fieldName := VIA_E,
1277
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1278
                };
584 garciay 1279
            } // end function f_setHeadersCANCEL
1280
 
1281
            /**
1282
             * @desc function sets header field for the next outgoing REGISTER message
1283
             * @param p_cSeq_s CSeq parameter to be applied
590 garciay 1284
             * @param p_emergency Set to true in case of emergency
584 garciay 1285
             */
599 tepelmann 1286
            function f_setHeaders_REGISTER(
1287
                inout CSeq p_cSeq_s,
1288
                boolean p_emergency := false
1289
            ) runs on SipComponent  {
584 garciay 1290
                var SemicolonParam_List v_params;
1291
 
599 tepelmann 1292
                f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via
584 garciay 1293
                vc_requestUri := {
1294
                    scheme := c_sipScheme,
599 tepelmann 1295
                    components := {
1296
                        sip := {
1297
                            userInfo := omit,
1298
                            hostPort := {
1299
                                host := vc_userprofile.registrarDomain,
1300
                                portField := omit
1301
                            }
1302
                        }
1303
                    },
584 garciay 1304
                    urlParameters := omit,
1305
                    headers := omit
505 rennoch 1306
                };
584 garciay 1307
 
1308
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1309
 
599 tepelmann 1310
                vc_callId := {
1311
                    fieldName := CALL_ID_E,
607 nikolajev 1312
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1313
                };
1314
                vc_callIdReg := vc_callId; // remember callId for de-registration
584 garciay 1315
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
1316
                vc_cancel_To := vc_to;
599 tepelmann 1317
                v_params := {
1318
                    {
1319
                        id := c_tagId,
1320
                        paramValue := f_getRndTag()
1321
                    }
1322
                };
1323
                vc_from := {
1324
                    fieldName := FROM_E,
1325
                    addressField := vc_to.addressField,
1326
                    fromParams := v_params
1327
                };
584 garciay 1328
 
1329
                if (not vc_firstREGISTER_sent) {
590 garciay 1330
                    if (p_emergency) {
599 tepelmann 1331
                        v_params := {
1332
                            {
1333
                                "sos",
1334
                                omit
1335
                            }
1336
                        };
590 garciay 1337
                        vc_contact.contactBody.contactAddresses[0].addressField.addrSpecUnion.urlParameters := v_params;
599 tepelmann 1338
                    }
1339
                    else {
1340
                        v_params := {
1341
                            {
1342
                                id := c_expiresId,
1343
                                paramValue := c_shortRegistration
1344
                            }
1345
                        };
590 garciay 1346
                        vc_contact.contactBody.contactAddresses[0].contactParams := v_params;
1347
                    }
584 garciay 1348
                }
1349
 
599 tepelmann 1350
                vc_firstREGISTER_sent := true; // f_setHeaders_Register is called in deREGISTER function
1351
                vc_authorization := {
1352
                    fieldName := AUTHORIZATION_E,
1353
                    body := {f_calculatecCredentials_empty(vc_userprofile)}
1354
                };
584 garciay 1355
 
1356
                vc_via_REG := vc_via;
1357
            } // end function setHeaders_REGISTER
1358
 
1359
            /**
1360
             * @desc function sets via, cseq and authorization header for the next outgoing (protected) REGISTER
1361
             * @verdict
1362
             */
600 nikolajev 1363
            function f_setHeaders_2ndREGISTER(
1364
                inout CSeq p_cSeq_s
1365
            ) runs on SipComponent  {
584 garciay 1366
                var CommaParam_List v_challenge;
1367
 
599 tepelmann 1368
                // Increment CSeq sequence number
584 garciay 1369
                p_cSeq_s.seqNumber := p_cSeq_s.seqNumber + 1;
1370
                vc_cSeq := p_cSeq_s;
1371
 
1372
                vc_requestUri := {
1373
                    scheme := c_sipScheme,
599 tepelmann 1374
                    components := {
1375
                        sip := {
1376
                            userInfo := omit,
1377
                            hostPort := {
1378
                                host := vc_userprofile.registrarDomain,
1379
                                portField := omit
1380
                            }
1381
                        }
1382
                    },
584 garciay 1383
                    urlParameters := omit,
1384
                    headers := omit
1385
                };
1386
 
599 tepelmann 1387
                // new branch tag due to different branch tag in new REGISTER method
584 garciay 1388
                vc_branch := c_branchCookie & f_getRndTag();
1389
 
599 tepelmann 1390
                vc_via_REG := {
1391
                    fieldName := VIA_E,
1392
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1393
                };
584 garciay 1394
 
599 tepelmann 1395
                // Extract challenge and calculate credentials for a response.
584 garciay 1396
                v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln;
1397
 
1398
 
599 tepelmann 1399
                // Prepair right answer
1400
                vc_authorization := {
1401
                    fieldName := AUTHORIZATION_E,
1402
                    body := {f_calculatecCredentials(vc_userprofile, "REGISTER", v_challenge)}
1403
                };
584 garciay 1404
            } // end function f_setHeaders_2ndREGISTER
1405
 
1406
            /**
599 tepelmann 1407
             * @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 1408
             * @verdict
1409
             */
600 nikolajev 1410
            function f_setHeaders_2ndREGISTER_wo_response(
1411
            ) runs on SipComponent  {
584 garciay 1412
                var CommaParam_List v_challenge;
1413
 
1414
                vc_branch := c_branchCookie & f_getRndTag();
1415
 
599 tepelmann 1416
                vc_via_REG := {
1417
                    fieldName := VIA_E,
1418
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1419
                };
584 garciay 1420
 
1421
                if (ischosen(vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge))
599 tepelmann 1422
                // Extract challenge and calculate credentials for a response.
584 garciay 1423
                {
1424
                    v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
599 tepelmann 1425
                }
1426
                else {
584 garciay 1427
                    v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.digestCln;
1428
                }
1429
 
599 tepelmann 1430
                // Increment CSeq sequence number
584 garciay 1431
                vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
1432
 
599 tepelmann 1433
                // Prepair right answer
1434
                vc_authorization := {
1435
                    fieldName := AUTHORIZATION_E,
1436
                    body := {f_calculatecCredentials_wo_response(vc_userprofile, "REGISTER", v_challenge)}
1437
                };
584 garciay 1438
            } // end function f_setHeaders_2ndREGISTER_wo_response
1439
 
1440
            /**
1441
             * @desc function sets via, cseq and authorization header with different private name for the next outgoing (protected) REGISTER
1442
             * @verdict
1443
             */
600 nikolajev 1444
            function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName(
1445
            ) runs on SipComponent  {
584 garciay 1446
                var CommaParam_List v_challenge;
1447
 
1448
                vc_branch := c_branchCookie & f_getRndTag();
1449
 
1450
                vc_requestUri := {
1451
                    scheme := c_sipScheme,
599 tepelmann 1452
                    components := {
1453
                        sip := {
1454
                            userInfo := omit,
1455
                            hostPort := {
1456
                                host := vc_userprofile.registrarDomain,
1457
                                portField := omit
1458
                            }
1459
                        }
1460
                    },
584 garciay 1461
                    urlParameters := omit,
1462
                    headers := omit
1463
                };
1464
 
599 tepelmann 1465
                vc_via_REG := {
1466
                    fieldName := VIA_E,
1467
                    viaBody := {valueof(m_ViaBody_currIpaddr(vc_branch, vc_userprofile))}
1468
                };
584 garciay 1469
 
599 tepelmann 1470
                // Extract challenge and calculate credentials for a response.
584 garciay 1471
                v_challenge := vc_response.msgHeader.wwwAuthenticate.challenge.otherChallenge.authParams;
1472
 
599 tepelmann 1473
                // Increment CSeq sequence number
584 garciay 1474
                vc_cSeq.seqNumber := vc_cSeq.seqNumber + 1;
1475
 
599 tepelmann 1476
                // Prepair right answer
1477
                vc_authorization := {
1478
                    fieldName := AUTHORIZATION_E,
1479
                    body := {f_calculatecCredentialsAndChangeUserName(vc_userprofile, "REGISTER", v_challenge)}
1480
                };
584 garciay 1481
            } // end function f_setHeaders_2ndREGISTER_authorizationWithDifferentUserName
1482
 
1483
 
1484
            /**
1485
             * @desc function sets header fields for the next outgoing REGISTER (de-registration)
1486
             * @param p_cSeq_s cSeq to be used
1487
             * @verdict
1488
             */
600 nikolajev 1489
            function f_setHeaders_deREGISTER(
1490
                inout CSeq p_cSeq_s
1491
            ) runs on SipComponent  {
584 garciay 1492
                var SemicolonParam_List v_params;
1493
 
599 tepelmann 1494
                f_setHeadersGeneral(p_cSeq_s, "REGISTER"); // cseq, contact, branch, via
1495
                // TODO STF471 change: to be checked!!! Related to increase nonce count
1496
                // reset authorization header to not use nonce from registration (otherwise we have to increase nc)
1497
                vc_authorization := {
1498
                    fieldName := AUTHORIZATION_E,
1499
                    body := {f_calculatecCredentials_empty(vc_userprofile)}
1500
                };
584 garciay 1501
                vc_requestUri := {
1502
                    scheme := c_sipScheme,
599 tepelmann 1503
                    components := {
1504
                        sip := {
1505
                            userInfo := omit,
1506
                            hostPort := {
1507
                                host := vc_userprofile.registrarDomain,
1508
                                portField := omit
1509
                            }
1510
                        }
1511
                    },
584 garciay 1512
                    urlParameters := omit,
1513
                    headers := omit
1514
                };
1515
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
599 tepelmann 1516
                v_params := {
1517
                    {
1518
                        id := c_tagId,
1519
                        paramValue := f_getRndTag()
1520
                    }
1521
                };
1522
                vc_from := {
1523
                    fieldName := FROM_E,
1524
                    addressField := vc_to.addressField,
1525
                    fromParams := v_params
1526
                };
584 garciay 1527
 
599 tepelmann 1528
                vc_contact := {
1529
                    fieldName := CONTACT_E,
1530
                    contactBody := {wildcard := "*"}
1531
                };
584 garciay 1532
            } // end function f_setHeaders_deREGISTER
1533
 
1534
 
1535
            /**
1536
             * @desc setting of general and basic Invite header fields in additon to the addresses (To, From, ReqUri)
1537
             * @param p_cSeq_s
1538
             */
600 nikolajev 1539
            function f_setHeadersINVITE(
1540
                inout CSeq p_cSeq_s
1541
            ) runs on SipComponent  {
599 tepelmann 1542
                f_setHeadersGeneral(p_cSeq_s, "INVITE"); // cseq, contact, branch, via
1543
                vc_callId := {
1544
                    fieldName := CALL_ID_E,
607 nikolajev 1545
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1546
                };
584 garciay 1547
 
1548
                vc_cancel_To := vc_to;
1549
                vc_caller_To := vc_to;
1550
 
1551
                vc_caller_From := vc_from;
1552
 
599 tepelmann 1553
                if (ischosen(vc_requestUri.components.sip)) {
1554
                    // sip/sips call
590 garciay 1555
                    vc_reqHostPort := vc_requestUri.components.sip.hostPort;
599 tepelmann 1556
                }
1557
                else if (ischosen(vc_requestUri.components.urn)) {
1558
                    // Emergency call
590 garciay 1559
                    vc_reqUrnUri := vc_requestUri.components.urn;
599 tepelmann 1560
                }
1561
                else {
607 nikolajev 1562
                    log("*** " & __SCOPE__ &" INFO:f_setHeadersINVITE: unsupported field: ", vc_requestUri," ***");
590 garciay 1563
                    setverdict(fail);
1564
                }
592 tepelmann 1565
            }
584 garciay 1566
 
1567
            /**
1568
             * @desc setting of general and basic Update header fields in additon to the addresses (To, From, ReqUri)
1569
             * @param p_cSeq_s
1570
             */
600 nikolajev 1571
            function f_setHeadersUPDATE(
1572
                inout CSeq p_cSeq_s
1573
            ) runs on SipComponent  {
599 tepelmann 1574
                f_setHeadersGeneral(p_cSeq_s, "UPDATE"); // cseq, contact, branch, via
1575
                vc_callId := {
1576
                    fieldName := CALL_ID_E,
607 nikolajev 1577
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1578
                };
584 garciay 1579
 
1580
                vc_cancel_To := vc_to;
1581
                vc_caller_To := vc_to;
1582
 
1583
                vc_caller_From := vc_from;
1584
 
1585
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1586
            } // end function f_setHeadersUPDATE
1587
 
1588
            /**
1589
             * @desc setting of general and basic Message header fields in additon to the addresses (To, From, ReqUri)
1590
             * @param p_cSeq_s
1591
             */
600 nikolajev 1592
            function f_setHeadersMESSAGE(
1593
                inout CSeq p_cSeq_s
1594
            ) runs on SipComponent  {
599 tepelmann 1595
                f_setHeadersGeneral(p_cSeq_s, "MESSAGE"); // cseq, contact, branch, via
1596
                vc_callId := {
1597
                    fieldName := CALL_ID_E,
607 nikolajev 1598
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1599
                };
584 garciay 1600
 
1601
                vc_cancel_To := vc_to;
1602
                vc_caller_To := vc_to;
1603
 
1604
                vc_caller_From := vc_from;
1605
 
1606
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1607
            } // end function f_setHeadersMESSAGE
1608
 
1609
            /**
1610
             * @desc setting of general and basic Notify header fields in additon to the addresses (To, From, ReqUri)
1611
             * @param p_cSeq_s
1612
             */
600 nikolajev 1613
            function f_setHeadersNOTIFY(
1614
                inout CSeq p_cSeq_s
1615
            ) runs on SipComponent  {
599 tepelmann 1616
                f_setHeadersGeneral(p_cSeq_s, "NOTIFY"); // cseq, contact, branch, via
584 garciay 1617
                vc_cancel_To := vc_to;
1618
                vc_caller_To := vc_to;
1619
                vc_caller_From := vc_from;
1620
 
1621
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1622
            } // end function f_setHeadersNOTIFY
1623
 
1624
            /**
1625
             * @desc setting of general and basic Publish header fields in additon to the addresses (To, From, ReqUri)
1626
             * @param p_cSeq_s
1627
             */
600 nikolajev 1628
            function f_setHeadersPUBLISH(
1629
                inout CSeq p_cSeq_s
1630
            ) runs on SipComponent  {
599 tepelmann 1631
                f_setHeadersGeneral(p_cSeq_s, "PUBLISH"); // cseq, contact, branch, via
584 garciay 1632
                // after SUBSCRIBE message callid shall be same
599 tepelmann 1633
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1634
                vc_cancel_To := vc_to;
1635
                vc_caller_To := vc_to;
1636
 
1637
                vc_caller_From := vc_from;
1638
 
1639
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1640
            } // end function f_setHeadersPUBLISH
1641
 
1642
            /**
1643
             * @desc function sets header field for the next outgoing SUBSCRIBE message
1644
             * @param p_cSeq_s CSeq parameter to be applied
1645
             */
600 nikolajev 1646
            function f_setHeaders_SUBSCRIBE(
1647
                inout CSeq p_cSeq_s
1648
            ) runs on SipComponent  {
584 garciay 1649
                var SemicolonParam_List v_params;
1650
 
599 tepelmann 1651
                f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via
584 garciay 1652
                vc_requestUri := valueof(m_SipUrl_currDomain(vc_userprofile));
1653
 
1654
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1655
 
599 tepelmann 1656
                vc_callId := {
1657
                    fieldName := CALL_ID_E,
607 nikolajev 1658
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1659
                };
584 garciay 1660
 
599 tepelmann 1661
                // TODO STF471 change
1662
                // store callId from Subscribe message
584 garciay 1663
                vc_callIdSub := vc_callId;
1664
 
1665
                vc_to := valueof(m_To(m_SipUrl_currDomain(vc_userprofile)));
1666
                vc_cancel_To := vc_to;
599 tepelmann 1667
                v_params := {
1668
                    {
1669
                        id := c_tagId,
1670
                        paramValue := f_getRndTag()
1671
                    }
1672
                };
1673
                vc_from := {
1674
                    fieldName := FROM_E,
1675
                    addressField := vc_to.addressField,
1676
                    fromParams := v_params
1677
                };
584 garciay 1678
            } // end function setHeaders_SUBSCRIBE
1679
 
1680
            /**
1681
             * @desc setting of general and basic Subscribe header fields in additon to the addresses (To, From, ReqUri)
1682
             * @param p_cSeq_s
1683
             */
600 nikolajev 1684
            function f_setHeadersSUBSCRIBE(
1685
                inout CSeq p_cSeq_s
1686
            ) runs on SipComponent  {
599 tepelmann 1687
                f_setHeadersGeneral(p_cSeq_s, "SUBSCRIBE"); // cseq, contact, branch, via
1688
                vc_callId := {
1689
                    fieldName := CALL_ID_E,
607 nikolajev 1690
                    callid := f_getRndCallId() & c_AT & vc_userprofile.currIpaddr
599 tepelmann 1691
                };
584 garciay 1692
 
1693
                vc_cancel_To := vc_to;
1694
                vc_caller_To := vc_to;
1695
 
1696
                vc_caller_From := vc_from;
1697
 
1698
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1699
            } // end function f_setHeadersMESSAGE
1700
 
1701
            /**
1702
             * @desc setting of general and basic REFER header fields in additon to the addresses (To, From, ReqUri)
1703
             * @param p_cSeq_s
1704
             */
600 nikolajev 1705
            function f_setHeadersREFER(
1706
                inout CSeq p_cSeq_s
1707
            ) runs on SipComponent  {
599 tepelmann 1708
                f_setHeadersGeneral(p_cSeq_s, "REFER"); // cseq, contact, branch, via
1709
                //      vc_callId := { fieldName:=CALL_ID_E, callid:=f_getRndCallId(p_cSeq_s) & c_AT & vc_userprofile.currIpaddr };
584 garciay 1710
                vc_cancel_To := vc_to;
1711
                vc_caller_To := vc_to;
1712
 
1713
                vc_caller_From := vc_from;
1714
 
1715
                vc_reqHostPort := vc_requestUri.components.sip.hostPort;
1716
            } // end function f_setHeadersREFER
1717
 
1718
            /**
1719
             * @desc This function reads all necessary headers from the received REGISTER message and generate the tag for the answer
1720
             * @param p_Request REGISTER that has been received
1721
             */
600 nikolajev 1722
            function f_setHeadersOnReceiptOfREGISTER(
1723
                Request p_Request
1724
            ) runs on SipComponent  {
584 garciay 1725
 
1726
                f_setHeadersOnReceiptOfRequest(p_Request);
1727
 
1728
                vc_callId := p_Request.msgHeader.callId;
1729
                vc_caller_From := vc_from;
1730
                f_addTagInTo(vc_to);
1731
                vc_caller_To := vc_to;
1732
                vc_requestUri := p_Request.requestLine.requestUri;
1733
 
1734
                vc_cancel_To := p_Request.msgHeader.toField;
1735
 
1736
                if (isvalue(p_Request.msgHeader.contact) and (not ischosen(p_Request.msgHeader.contact.contactBody.wildcard))) {
1737
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1738
                }
1739
 
599 tepelmann 1740
                // update callee information and pick up tag if the call need to be canceled
1741
                vc_callee_To := {
1742
                    fieldName := TO_E,
1743
                    addressField := vc_caller_From.addressField,
1744
                    toParams := vc_caller_From.fromParams
1745
                };
584 garciay 1746
 
599 tepelmann 1747
                vc_callee_From := {
1748
                    fieldName := FROM_E,
1749
                    addressField := vc_caller_To.addressField,
1750
                    fromParams := vc_caller_To.toParams
1751
                };
584 garciay 1752
 
1753
                if (isvalue(p_Request.msgHeader.authorization)) {
598 tepelmann 1754
                    vc_authorization := valueof(p_Request.msgHeader.authorization);
584 garciay 1755
                }
1756
            } // end f_setHeadersOnReceiptOfREGISTER
1757
 
1758
            /**
1759
             * @desc This function reads all necessary headers from the received SUBSCRIBE message and generate the tag for the answer
1760
             * @param p_Request SUBSCRIBE that has been received
1761
             */
600 nikolajev 1762
            function f_setHeadersOnReceiptOfSUBSCRIBE(
1763
                Request p_Request
1764
            ) runs on SipComponent  {
584 garciay 1765
 
1766
                f_setHeadersOnReceiptOfRequest(p_Request);
1767
 
1768
                vc_callId := p_Request.msgHeader.callId;
1769
                vc_caller_From := vc_from;
1770
                f_addTagInTo(vc_to);
1771
                vc_caller_To := vc_to;
1772
                vc_requestUri := p_Request.requestLine.requestUri;
1773
 
1774
                vc_cancel_To := p_Request.msgHeader.toField;
1775
 
1776
                if (isvalue(p_Request.msgHeader.contact)) {
1777
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1778
                }
1779
 
599 tepelmann 1780
                // update callee information and pick up tag if the call need to be canceled
1781
                vc_callee_To := {
1782
                    fieldName := TO_E,
1783
                    addressField := vc_caller_From.addressField,
1784
                    toParams := vc_caller_From.fromParams
1785
                };
584 garciay 1786
 
599 tepelmann 1787
                vc_callee_From := {
1788
                    fieldName := FROM_E,
1789
                    addressField := vc_caller_To.addressField,
1790
                    fromParams := vc_caller_To.toParams
1791
                };
584 garciay 1792
            } // end f_setHeadersOnReceiptOfSUBSCRIBE
1793
 
600 nikolajev 1794
            function f_setHeadersOnReceiptOfREFER(
1795
                Request p_Request
1796
            ) runs on SipComponent  {
584 garciay 1797
 
1798
                f_setHeadersOnReceiptOfRequest(p_Request);
1799
 
1800
                vc_requestUri := p_Request.requestLine.requestUri;
1801
                vc_cancel_To := p_Request.msgHeader.toField;
1802
 
1803
                if (isvalue(p_Request.msgHeader.contact)) {
1804
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1805
                    vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1806
                }
1807
 
599 tepelmann 1808
                // update callee information and pick up tag if the call need to be canceled
1809
                vc_callee_To := {
1810
                    fieldName := TO_E,
1811
                    addressField := vc_caller_From.addressField,
1812
                    toParams := vc_caller_From.fromParams
1813
                };
584 garciay 1814
 
599 tepelmann 1815
                vc_callee_From := {
1816
                    fieldName := FROM_E,
1817
                    addressField := vc_caller_To.addressField,
1818
                    fromParams := vc_caller_To.toParams
1819
                };
584 garciay 1820
            } // end f_setHeadersOnReceiptOfREFER
1821
 
1822
            /**
1823
             * @desc function reads all necessary headers from the received INVITE message and generate the tag for the answer
1824
             * @param p_Request received INVITE message
1825
             * @verdict
1826
             */
600 nikolajev 1827
            function f_setHeadersOnReceiptOfINVITE(
1828
                Request p_Request
1829
            ) runs on SipComponent  {
607 nikolajev 1830
                var integer i, j;
1831
                var integer v_length;
1832
 
584 garciay 1833
                f_setHeadersOnReceiptOfRequest(p_Request);
1834
 
1835
                vc_callId := p_Request.msgHeader.callId;
1836
 
1837
                vc_requestUri2 := p_Request.requestLine.requestUri;
1838
 
1839
                vc_cancel_To := p_Request.msgHeader.toField;
1840
                f_addTagInTo(vc_to);
1841
                vc_caller_From := vc_from;
1842
                vc_caller_To := vc_to;
1843
 
1844
                if (isvalue(p_Request.msgHeader.contact)) {
1845
                    vc_reqHostPort := f_getContactAddr(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1846
                    vc_requestUri := f_getContactUri(p_Request.msgHeader.contact.contactBody.contactAddresses[0]);
1847
                }
1848
 
599 tepelmann 1849
                // update callee information and pick up tag if the call need to be canceled
1850
                vc_callee_To := {
1851
                    fieldName := TO_E,
1852
                    addressField := vc_caller_From.addressField,
1853
                    toParams := vc_caller_From.fromParams
1854
                };
584 garciay 1855
 
599 tepelmann 1856
                vc_callee_From := {
1857
                    fieldName := FROM_E,
1858
                    addressField := vc_caller_To.addressField,
1859
                    fromParams := vc_caller_To.toParams
1860
                };
584 garciay 1861
 
1862
                if (isvalue(p_Request.msgHeader.privacy)) {
1863
                    vc_privacy := p_Request.msgHeader.privacy;
1864
                }
1865
 
1866
                if (isvalue(p_Request.messageBody)) {
599 tepelmann 1867
                    // cleaning of attributes before assignment
584 garciay 1868
                    if (isvalue(vc_sdp_remote.media_list)) {
607 nikolajev 1869
                        v_length := lengthof(vc_sdp_remote.media_list);
1870
                        for (i := 0; i < v_length; i := i + 1) {
584 garciay 1871
                            if (isvalue(vc_sdp_remote.media_list[i].attributes)) {
1872
                                vc_sdp_remote.media_list[i].attributes := omit;
1873
                            }
1874
                        }
1875
                    }
1876
 
599 tepelmann 1877
                    // save SDP if present
584 garciay 1878
                    if (ischosen(p_Request.messageBody.sdpMessageBody)) {
1879
                        vc_sdp_remote := p_Request.messageBody.sdpMessageBody;
1880
                        vc_sdp_remote_is_valid := true;
1881
                        f_prepare_SDP_answer();
1882
                    }
1883
 
599 tepelmann 1884
                    // save XML if present
584 garciay 1885
                    if (ischosen(p_Request.messageBody.xmlBody)) {
1886
                        vc_xml_remote := p_Request.messageBody.xmlBody;
1887
                    }
1888
 
1889
                    if (ischosen(p_Request.messageBody.mimeMessageBody)) {
1890
 
607 nikolajev 1891
                        for (j := 0; j < lengthof(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) {
584 garciay 1892
                            if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) {
1893
                                vc_sdp_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
1894
                                vc_sdp_remote_is_valid := true;
1895
                                f_prepare_SDP_answer();
1896
                            }
1897
                            if (match(p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) {
1898
                                vc_xml_remote := p_Request.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
1899
                            }
1900
                        }
1901
                    }
1902
                }
1903
 
1904
                if (isvalue(p_Request.msgHeader.supported.optionsTags)) {
607 nikolajev 1905
                    for (i := lengthof(p_Request.msgHeader.supported.optionsTags); i > 0; i := i - 1) {
584 garciay 1906
                        if (p_Request.msgHeader.supported.optionsTags[i - 1] == "100rel") {
1907
                            vc_supported_100rel := true;
1908
                        }
1909
                        if (p_Request.msgHeader.supported.optionsTags[i - 1] == "precondition") {
1910
                            vc_supported_precondition := true;
1911
                        }
1912
                    }
1913
                }
1914
            } // end f_setHeadersOnReceiptOfINVITE
1915
 
1916
            /**
1917
             * @desc function reads header field of a received BYE message
1918
             * @param p_Request received BYE
1919
             */
600 nikolajev 1920
            function f_setHeadersOnReceiptOfBYE(
1921
                Request p_BYE_Request
1922
            ) runs on SipComponent  {
584 garciay 1923
 
1924
                f_setHeadersOnReceiptOfRequest(p_BYE_Request);
1925
                vc_callId := p_BYE_Request.msgHeader.callId;
1926
            } // end f_setHeadersOnReceiptOfBYE
1927
 
1928
            /**
1929
             * @desc function reads header field from an incoming Request message
1930
             * @param p_Request received Request message
1931
             */
600 nikolajev 1932
            function f_setHeadersOnReceiptOfRequest(
1933
                Request p_Request
1934
            ) runs on SipComponent  {
584 garciay 1935
                vc_request := p_Request;
1936
                vc_callId := p_Request.msgHeader.callId;
599 tepelmann 1937
                vc_cSeq := valueof(p_Request.msgHeader.cSeq); // CSeq is mandatory
584 garciay 1938
                vc_iut_CSeq := p_Request.msgHeader.cSeq;
1939
                vc_from := p_Request.msgHeader.fromField;
1940
                vc_caller_From := p_Request.msgHeader.fromField;
1941
                vc_to := p_Request.msgHeader.toField;
1942
                vc_caller_To := p_Request.msgHeader.toField;
1943
                vc_via := p_Request.msgHeader.via;
599 tepelmann 1944
                // update sent_label according to received via header field
584 garciay 1945
                f_getViaReplyAddr(vc_via.viaBody, vc_sent_label);
1946
 
599 tepelmann 1947
                // Catch route
584 garciay 1948
                vc_boo_recordRoute := false;
1949
 
1950
                // add tag field into To header if tag is not present
1951
                if (not (isvalue(p_Request.msgHeader.toField.toParams))) {
599 tepelmann 1952
                    vc_to.toParams := {
1953
                        {
1954
                            id := c_tagId,
1955
                            paramValue := f_getRndTag()
1956
                        }
1957
                    };
584 garciay 1958
                    vc_caller_To := vc_to;
1959
                }
1960
                if (isvalue(p_Request.msgHeader.recordRoute)) {
1961
                    vc_boo_recordRoute := true;
1962
                    vc_recordRoute := p_Request.msgHeader.recordRoute;
1963
                }
1964
            } // end f_setHeadersOnReceiptOfRequest
1965
 
1966
            /**
1967
             * @desc functions reads header fields from an incoming Response message
1968
             * @param p_cSeq
1969
             * @param p_response received response message
1970
             * @verdict
1971
             */
599 tepelmann 1972
            function f_setHeadersOnReceiptOfResponse(
607 nikolajev 1973
                inout CSeq p_cSeq,//TODO: do I remove this parameter, although it does nothing
599 tepelmann 1974
                Response p_response
1975
            ) runs on SipComponent  {
607 nikolajev 1976
                var integer i, j, v_nbroute;
584 garciay 1977
                var template(omit) Contact v_contact;
599 tepelmann 1978
                // only for local purpose
584 garciay 1979
                vc_response := p_response;
599 tepelmann 1980
                // vc_cSeq := p_cSeq; //must not save global c_seq because it can overwrite temporary cSeq
584 garciay 1981
                vc_to := p_response.msgHeader.toField;
1982
                vc_from := p_response.msgHeader.fromField;
1983
                vc_caller_To := vc_to;
1984
                vc_caller_From := vc_from;
1985
 
1986
                if (isvalue(p_response.msgHeader.contact)) {
1987
                    v_contact := p_response.msgHeader.contact;
1988
                    if (ischosen(v_contact.contactBody.contactAddresses)) {
1989
                        vc_reqHostPort := f_getContactAddr(valueof(v_contact.contactBody.contactAddresses[0]));
1990
                        vc_requestUri := f_getContactUri(valueof(v_contact.contactBody.contactAddresses[0]));
1991
                    }
599 tepelmann 1992
                }
1993
                else {
1994
                    if (ischosen(vc_to.addressField.addrSpecUnion.components.sip)) {
1995
                        // sip/sips call
1996
                        vc_reqHostPort := vc_to.addressField.addrSpecUnion.components.sip.hostPort;
584 garciay 1997
                    }
599 tepelmann 1998
                    else if (ischosen(vc_to.addressField.addrSpecUnion.components.urn)) {
1999
                        // Emergency call
2000
                        vc_reqUrnUri := vc_to.addressField.addrSpecUnion.components.urn;
2001
                    }
2002
                    else {
607 nikolajev 2003
                        log("*** f_setHeadersOnReceiptOfResponse: INFO: unsupported field: ", vc_to, " ***");
599 tepelmann 2004
                        setverdict(fail);
2005
                    }
2006
                    vc_requestUri := vc_to.addressField.addrSpecUnion;
584 garciay 2007
                }
2008
 
599 tepelmann 2009
                vc_callee_To := {
2010
                    fieldName := TO_E,
2011
                    addressField := vc_caller_From.addressField,
2012
                    toParams := vc_caller_From.fromParams
2013
                };
584 garciay 2014
 
599 tepelmann 2015
                vc_callee_From := {
2016
                    fieldName := FROM_E,
2017
                    addressField := vc_caller_To.addressField,
2018
                    fromParams := vc_caller_To.toParams
2019
                };
584 garciay 2020
 
2021
                vc_via := p_response.msgHeader.via;
2022
 
599 tepelmann 2023
                // Route Management
584 garciay 2024
                if (isvalue(p_response.msgHeader.recordRoute)) {
2025
                    vc_recordRoute := p_response.msgHeader.recordRoute;
2026
                    v_nbroute := lengthof(vc_recordRoute.routeBody);
599 tepelmann 2027
                    // copy and reverse the order of the routes in route header
607 nikolajev 2028
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2029
                        j := v_nbroute - 1 - i;
2030
                        vc_route.routeBody[j] := vc_recordRoute.routeBody[i];
584 garciay 2031
                    }
2032
                    vc_route.fieldName := ROUTE_E;
2033
                    vc_boo_recordRoute := true;
2034
                    vc_boo_route := true;
599 tepelmann 2035
                }
2036
                else {
584 garciay 2037
                    vc_boo_recordRoute := false;
2038
                    vc_boo_route := false;
2039
                }
2040
 
2041
 
599 tepelmann 2042
                // extentions due to new fields in PRACK and UPDATE messages
584 garciay 2043
                if (isvalue(p_response.msgHeader.rSeq)) {
2044
                    vc_rAck := {
2045
                        fieldName := RACK_E,
2046
                        responseNum := valueof(p_response.msgHeader.rSeq).responseNum,
2047
                        seqNumber := valueof(p_response.msgHeader.cSeq).seqNumber,
2048
                        method := valueof(p_response.msgHeader.cSeq).method
2049
                    };
2050
                }
2051
 
599 tepelmann 2052
                // extentions due to new HistoryInfo fields 180 or 200OK messages
584 garciay 2053
                if (isvalue(p_response.msgHeader.historyInfo)) {
2054
                    vc_historyInfoList := valueof(p_response.msgHeader.historyInfo).historyInfoList;
2055
                    vc_history_is_valid := true;
599 tepelmann 2056
                }
2057
                else {
584 garciay 2058
                    vc_history_is_valid := false;
2059
                }
2060
 
599 tepelmann 2061
                // sdpMessageBody answer
584 garciay 2062
                if (isvalue(p_response.messageBody)) {
2063
                    if (ischosen(p_response.messageBody.sdpMessageBody)) {
2064
                        vc_sdp_remote := p_response.messageBody.sdpMessageBody;
2065
                        vc_sdp_remote_is_valid := true;
2066
                    }
2067
 
2068
                    if (ischosen(p_response.messageBody.xmlBody)) {
2069
                        vc_xml_remote := p_response.messageBody.xmlBody;
2070
                    }
2071
 
2072
                    if (ischosen(p_response.messageBody.mimeMessageBody)) {
2073
 
607 nikolajev 2074
                        for (j := 0; j < lengthof(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList); j := j + 1) {
584 garciay 2075
                            if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_sdpApplication)) {
2076
                                vc_sdp_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.sdpMessageBody;
2077
                            }
2078
                            if (match(p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].content_type, c_xmlApplication)) {
2079
                                vc_xml_remote := p_response.messageBody.mimeMessageBody.mimeEncapsulatedList[j].mime_encapsulated_part.xmlBody;
2080
                            }
2081
                        }
2082
                    }
2083
                }
2084
            } // end function f_setHeadersOnReceiptOfResponse
2085
 
2086
            /**
2087
             * @desc functions reads ServiceRoute header field from an incoming 200 Response message in registration
2088
             * @param p_cSeq
2089
             * @param p_response received response message
2090
             */
599 tepelmann 2091
            function f_getServiceRouteMapIntoRouteInRegistration(
2092
                Response p_response
2093
            ) runs on SipComponent  {
607 nikolajev 2094
                var integer i, j, v_nbroute;
584 garciay 2095
                var template(omit) ServiceRoute v_serviceRoute;
2096
 
599 tepelmann 2097
                // Route Management
584 garciay 2098
                if (isvalue(p_response.msgHeader.serviceRoute)) {
2099
                    v_serviceRoute := p_response.msgHeader.serviceRoute;
2100
                    v_nbroute := lengthof(v_serviceRoute.routeBody);
599 tepelmann 2101
                    // copy and reverse the order of the routes in route header
607 nikolajev 2102
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2103
                        j := v_nbroute - 1 - i;
2104
                        vc_route.routeBody[j] := v_serviceRoute.routeBody[i];
584 garciay 2105
                    }
2106
                    vc_route.fieldName := ROUTE_E;
2107
                    vc_route_REG := vc_route;
2108
                    vc_boo_route := true;
2109
                }
2110
            } // end function f_getServiceRouteMapIntoRouteInRegistration
2111
 
2112
            /**
2113
             * @desc functions reads Route header field from an incoming Request message and generate RecordRoute
2114
             * @param p_cSeq
2115
             * @param p_request received request message
2116
             */
599 tepelmann 2117
            function f_getRouteMapIntoRecordRoute(
2118
                inout CSeq p_cSeq,
2119
                Request p_request
2120
            ) runs on SipComponent  {
607 nikolajev 2121
                var integer i, j, v_nbroute;
584 garciay 2122
                var template(omit) Route v_route;
2123
 
599 tepelmann 2124
                // Route Management
584 garciay 2125
                if (isvalue(p_request.msgHeader.route)) {
2126
                    v_route := p_request.msgHeader.route;
2127
                    v_nbroute := lengthof(v_route.routeBody);
599 tepelmann 2128
                    // copy and reverse the order of the routes in route header
607 nikolajev 2129
                    for (i := 0; i <= (v_nbroute - 1); i := i + 1) {
2130
                        j := v_nbroute - 1 - i;
2131
                        vc_recordRoute.routeBody[j] := v_route.routeBody[i];
584 garciay 2132
                    }
2133
                    vc_recordRoute.fieldName := RECORD_ROUTE_E;
2134
 
2135
                    vc_boo_recordRoute := true;
2136
                }
2137
            } // end function f_getRouteMapIntoRecordRoute
2138
 
599 tepelmann 2139
 
597 tepelmann 2140
        } // end group SetHeaders
2141
 
2142
 
599 tepelmann 2143
 
584 garciay 2144
    } // end group FieldOperations
2145
 
2146
    group SDPOperations {
2147
 
2148
        /**
2149
         * @desc check if message body include SDP attribute (2nd parameter) for any media
2150
         */
599 tepelmann 2151
        function f_check_attribute(
2152
            in SDP_Message p_sdp,
2153
            in template SDP_attribute p_attribute
600 nikolajev 2154
        ) runs on SipComponent
2155
        return boolean  {
607 nikolajev 2156
            var integer i, j;
584 garciay 2157
 
2158
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2159
                for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) {
584 garciay 2160
                    if (isvalue(p_sdp.media_list[j].attributes)) {
607 nikolajev 2161
                        for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) {
584 garciay 2162
                            if (match(p_sdp.media_list[j].attributes[i], p_attribute)) {
2163
                                return (true);
2164
                            }
2165
                        }
2166
                    }
2167
                }
2168
            }
2169
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2170
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2171
                    if (match(p_sdp.attributes[j], p_attribute)) {
2172
                        return (true);
2173
                    }
2174
                }
2175
            }
2176
 
2177
            return (false);
505 rennoch 2178
        }
9 rennoch 2179
 
584 garciay 2180
        /**
2181
         * @desc check if message body include SDP (session level) attribute (2nd parameter) for any media
2182
         */
599 tepelmann 2183
        function f_check_session_attribute(
2184
            in SDP_Message p_sdp,
2185
            in template SDP_attribute p_attribute
600 nikolajev 2186
        ) runs on SipComponent
2187
        return boolean  {
607 nikolajev 2188
            var integer j;
234 rennoch 2189
 
584 garciay 2190
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2191
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2192
                    if (match(p_sdp.attributes[j], p_attribute)) {
2193
                        return (true);
2194
                    }
2195
                }
2196
            }
9 rennoch 2197
 
584 garciay 2198
            return (false);
2199
        }
9 rennoch 2200
 
584 garciay 2201
        /**
2202
         * @desc identify an SDP direction attribute (session or first media attribute) in a SDP message and return its answer value
2203
         * @param p_sdp the SDP message that has been received
2204
         * @param p_attribute incoming SDP attribute that need to be used for the SDP direction (answer)
2205
         * @return the new attribute (to be send out) derived from the incoming SDP value
2206
         * @verdict
2207
         */
599 tepelmann 2208
        function f_get_attribute_answer(
2209
            in SDP_Message p_sdp,
2210
            in template SDP_attribute p_attribute
600 nikolajev 2211
        ) runs on SipComponent
2212
        return SDP_attribute  {
607 nikolajev 2213
            var integer i, j;
584 garciay 2214
            var template SDP_attribute v_attribute := p_attribute;
9 rennoch 2215
 
599 tepelmann 2216
            // check if the selected attribute is included in the SDP offer (session attributes)
584 garciay 2217
            if (isvalue(p_sdp.attributes)) {
607 nikolajev 2218
                for (j := 0; j < lengthof(p_sdp.attributes); j := j + 1) {
584 garciay 2219
                    if (match(p_sdp.attributes[j], p_attribute)) {
2220
                        v_attribute := p_sdp.attributes[j];
2221
                    }
2222
                }
599 tepelmann 2223
            }
2224
            else
2225
            // check if the selected attribute is included in the SDP offer (any of the media attributes)
584 garciay 2226
            {
2227
                if (isvalue(p_sdp.media_list)) {
607 nikolajev 2228
                    for (j := 0; j < lengthof(p_sdp.media_list); j := j + 1) {
584 garciay 2229
                        if (isvalue(p_sdp.media_list[j].attributes)) {
607 nikolajev 2230
                            for (i := 0; i < lengthof(p_sdp.media_list[j].attributes); i := i + 1) {
584 garciay 2231
                                if (match(p_sdp.media_list[j].attributes[i], p_attribute)) {
2232
                                    v_attribute := p_sdp.media_list[j].attributes[i];
2233
                                }
2234
                            }
2235
                        }
2236
                    }
2237
                }
2238
            }
9 rennoch 2239
 
584 garciay 2240
            select (valueof(v_attribute)) {
2241
                case (mw_attribute_sendonly) {
2242
                    return (valueof(m_attribute_recvonly));
2243
                }
2244
                case (mw_attribute_sendrecv) {
2245
                    return (valueof(m_attribute_sendrecv));
599 tepelmann 2246
                } // MRO
584 garciay 2247
                case (mw_attribute_inactive) {
2248
                    return (valueof(m_attribute_inactive));
599 tepelmann 2249
                } // MRO
584 garciay 2250
                case (mw_attribute_recvonly) {
2251
                    return (valueof(m_attribute_sendonly));
599 tepelmann 2252
                } // MRO
584 garciay 2253
            }
599 tepelmann 2254
            return (valueof(m_attribute_sendrecv)); // the default return value in case of missing attribute offer
584 garciay 2255
        }
9 rennoch 2256
 
584 garciay 2257
        /**
2258
         * @desc check if message body include SDP bandwidth (2nd parameter) either for the session or a media description
2259
         */
599 tepelmann 2260
        function f_check_bandwidth(
607 nikolajev 2261
            in SDP_Message p_loc_sdp,
2262
            in template SDP_bandwidth p_loc_bandw
600 nikolajev 2263
        ) runs on SipComponent
2264
        return boolean  {
607 nikolajev 2265
            var integer i, j;
2266
            if (isvalue(p_loc_sdp.bandwidth)) {
2267
                for (j := 0; j < lengthof(p_loc_sdp.bandwidth); j := j + 1) {
2268
                    if (match(p_loc_sdp.bandwidth[j], p_loc_bandw)) {
584 garciay 2269
                        return (true);
2270
                    }
2271
                }
2272
            }
607 nikolajev 2273
            if (isvalue(p_loc_sdp.media_list)) {
2274
                for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) {
2275
                    if (isvalue(p_loc_sdp.media_list[j].bandwidth)) {
2276
                        for (i := 0; i < lengthof(p_loc_sdp.media_list[j].bandwidth); i := i + 1) {
2277
                            if (match(p_loc_sdp.media_list[j].bandwidth[i], p_loc_bandw)) {
584 garciay 2278
                                return (true);
2279
                            }
2280
                        }
2281
                    }
2282
                }
2283
            }
2284
 
2285
            return (false);
2286
        }
2287
 
2288
        /**
2289
         * @desc check if message body include SDP media (2nd parameter)
2290
         */
599 tepelmann 2291
        function f_check_media(
607 nikolajev 2292
            in SDP_Message p_loc_sdp,
2293
            in template(present) SDP_media_desc p_loc_media
600 nikolajev 2294
        ) runs on SipComponent
2295
        return boolean  {
607 nikolajev 2296
            var integer j;
2297
            if (isvalue(p_loc_sdp.media_list)) {
2298
                for (j := 0; j < lengthof(p_loc_sdp.media_list); j := j + 1) {
2299
                    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 2300
                        return (true);
2301
                    }
2302
                }
2303
            }
2304
            return (false);
2305
        }
2306
 
2307
        /**
2308
         * @desc check if message body include precondition mechanism (a=des and a=curr) retrun true, else false
2309
         * @param loc_sdp SDP message
2310
         */
600 nikolajev 2311
        function f_check_precondition(
607 nikolajev 2312
            in SDP_Message p_loc_sdp
600 nikolajev 2313
        ) runs on SipComponent
2314
        return boolean  {
607 nikolajev 2315
            if (f_check_attribute(p_loc_sdp, mw_attribute_des) or f_check_attribute(p_loc_sdp, mw_attribute_curr)) {
584 garciay 2316
                return (true);
2317
            }
2318
 
2319
            return (false);
2320
        }
2321
 
2322
 
2323
        /**
2324
         * @desc check if message body include SDP media direction return true, else false
2325
         */
600 nikolajev 2326
        function f_check_media_direction(
607 nikolajev 2327
            in SDP_Message p_loc_sdp
600 nikolajev 2328
        ) runs on SipComponent
2329
        return boolean  {
584 garciay 2330
 
607 nikolajev 2331
            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 2332
                return (true);
2333
            }
2334
 
2335
            return (false);
2336
        }
2337
 
2338
        /**
2339
         * @desc copy media/attribute lines from remote to local SDP variable
2340
         */
599 tepelmann 2341
        function f_check_SDP(
607 nikolajev 2342
            integer p_loc_sdp,
2343
            integer p_loc_codec
600 nikolajev 2344
        ) runs on SipComponent
2345
        return boolean  {
607 nikolajev 2346
            var SDP_media_desc v_media := f_prepare_media(p_loc_sdp, p_loc_codec);
584 garciay 2347
            if (vc_sdp_remote.media_list[0].media_field.media != v_media.media_field.media) {
2348
                return false;
2349
            }
2350
            if (vc_sdp_remote.media_list[0].media_field.transport != v_media.media_field.transport) {
2351
                return false;
2352
            }
2353
            if (vc_sdp_remote.media_list[0].media_field.fmts != v_media.media_field.fmts) {
2354
                return false;
2355
            }
2356
 
2357
            return true;
2358
        }
2359
 
2360
        /**
2361
         * @desc replace the first curr media attribute with the given value.
2362
         * @param p_sdp SDP message to modify
2363
         * @param p_curr new curr attribute
2364
         */
599 tepelmann 2365
        function f_replace_curr_attribute(
2366
            inout SDP_Message p_sdp,
2367
            in SDP_attribute_curr p_curr
2368
        ) {
607 nikolajev 2369
            var integer i;
2370
            var integer v_mn;
584 garciay 2371
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2372
                v_mn := lengthof(p_sdp.media_list[0].attributes);
2373
                for (i := 0; i < v_mn; i := i + 1) {
584 garciay 2374
                    if (ischosen(p_sdp.media_list[0].attributes[i].curr)) {
2375
                        p_sdp.media_list[0].attributes[i].curr := p_curr;
607 nikolajev 2376
                        i := v_mn;
584 garciay 2377
                    }
2378
                }
2379
            }
2380
        }
2381
 
2382
        /**
2383
         * @desc append new media attribute to the first media description.
2384
         * @param p_sdp SDP message to modify
2385
         * @param p_att SDP attribute to appand
2386
         */
599 tepelmann 2387
        function f_append_media_attribute(
2388
            inout SDP_Message p_sdp,
2389
            in SDP_attribute p_att
2390
        ) {
607 nikolajev 2391
            var integer v_mn;
584 garciay 2392
            if (isvalue(p_sdp.media_list)) {
607 nikolajev 2393
                v_mn := lengthof(p_sdp.media_list[0].attributes);
2394
                p_sdp.media_list[0].attributes[v_mn] := p_att;
584 garciay 2395
            }
2396
        }
2397
 
2398
 
2399
        /**
2400
         * @desc append new media to the existing media list in SDP
2401
         */
599 tepelmann 2402
        function f_append_media(
607 nikolajev 2403
            inout SDP_Message p_loc_SDP,
2404
            template(value) SDP_media_desc p_loc_media
599 tepelmann 2405
        ) {
607 nikolajev 2406
            var integer v_mn := lengthof(p_loc_SDP.media_list);
2407
            p_loc_SDP.media_list[v_mn] := valueof(p_loc_media);
584 garciay 2408
        }
2409
 
2410
        /**
2411
         * @desc repare media/attribute lines
2412
         */
599 tepelmann 2413
        function f_prepare_media(
607 nikolajev 2414
            integer p_loc_sdp,
2415
            integer p_loc_codec
600 nikolajev 2416
        ) runs on SipComponent
2417
        return SDP_media_desc  {
599 tepelmann 2418
            var charstring v_codecs[32] := {"PCMU/8000", "GSM/8000", "G723/8000", "DVI4/8000", "DVI4/16000", "LPC/8000", "PCMA/8000", "G722/8000", "L16/44100/2", "L16/44100", "QCELP/8000", "CN/8000", "MPA/90000", "G728/8000", "DVI4/11025", "DVI4/22050", "G729/8000", "G726-40/8000", "G726-32/8000", "G726-24/8000", "G726-16/8000", "G726D/8000", "G726E/8000", "GSM-EFR/8000", "CelB/90000", "JPEG/90000", "Nv/90000", "H261/90000", "MPV/90000", "MP2T/90000", "H263/90000", "H263-1998/90000"};