blob: e6e8b53918eaee2305fd51902825ac8e892ba8a0 [file] [log] [blame]
Harald Welteb0d93602018-03-20 18:09:34 +01001module SIP_Templates {
2
3import from SIPmsg_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02004import from TCCConversion_Functions all;
5import from TCCOpenSecurity_Functions all;
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02006import from TCCDateTime_Functions all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02007import from Native_Functions all;
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01008import from Osmocom_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02009import from Misc_Helpers all;
Harald Welteb0d93602018-03-20 18:09:34 +010010
11/* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */
12type record SipAddr {
13 Addr_Union addr,
14 SemicolonParam_List params optional
15}
16
17const charstring c_SIP_VERSION := "SIP/2.0";
18
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020019template (value) GenericParam ts_Param(template (value) charstring id,
20 template (omit) charstring paramValue := omit) := {
21 id := id,
22 paramValue := paramValue
23}
24template (present) GenericParam tr_Param(template (present) charstring id := ?,
25 template charstring paramValue := *) := {
26 id := id,
27 paramValue := paramValue
28}
29function f_ts_Param_omit(template (value) charstring id,
30 template (omit) charstring paramValue := omit)
31 return template (omit) GenericParam
32{
33 if (istemplatekind(paramValue, "omit")) {
34 return omit;
35 }
36 return ts_Param(id, paramValue);
37}
38
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010039template (value) SipUrl ts_SipUrl(template (value) HostPort host_port,
40 template (omit) UserInfo user_info := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +010041 scheme := "sip",
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010042 userInfo := user_info,
43 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010044 urlParameters := omit,
45 headers := omit
46}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010047template (present) SipUrl tr_SipUrl(template (present) HostPort host_port := ?,
48 template UserInfo user_info := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +010049 scheme := "sip",
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010050 userInfo := user_info,
51 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010052 urlParameters := *,
53 headers := *
54}
55
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020056template (value) SipUrl ts_SipUrlHost(template (value) charstring host,
57 template (omit) integer portField := omit)
58 := ts_SipUrl(ts_HostPort(host, portField));
59
60function ts_SipUrl_from_Addr_Union(template (value) Addr_Union au)
61return template (value) SipUrl {
62 if (ischosen(au.nameAddr)) {
63 return au.nameAddr.addrSpec;
64 } else { /* au.addrSpecUnion */
65 return au.addrSpecUnion;
66 }
67}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010068
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +020069// [20.5]
70template (present) Allow tr_Allow(template Method_List methods := *) := {
71 fieldName := ALLOW_E,
72 methods := methods
73}
74template (value) Allow ts_Allow(template (omit) Method_List methods := omit) := {
75 fieldName := ALLOW_E,
76 methods := methods
77}
78
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020079template (value) Credentials ts_Credentials_DigestResponse(template (value) CommaParam_List digestResponse) := {
80 digestResponse := digestResponse
81}
82
83template (value) Credentials ts_Credentials_DigestResponseMD5(
84 template (value) charstring username,
85 template (value) charstring realm,
86 template (value) charstring nonce,
87 template (value) charstring uri,
88 template (value) charstring response,
89 template (value) charstring opaque,
90 template (value) charstring algorithm := "MD5",
91 template (value) charstring qop := "auth",
92 template (omit) charstring cnonce := omit,
93 template (omit) charstring nc := omit
94 ) := {
95 digestResponse := {
96 // Already added by digestResponse automatically:
97 //ts_Param("Digest", omit),
98 ts_Param("username", f_sip_str_quote(username)),
99 ts_Param("realm", f_sip_str_quote(realm)),
100 ts_Param("nonce", f_sip_str_quote(nonce)),
101 ts_Param("uri", f_sip_str_quote(uri)),
102 ts_Param("response", f_sip_str_quote(response)),
103 ts_Param("opaque", f_sip_str_quote(opaque)),
104 ts_Param("algorithm", algorithm),
105 ts_Param("qop", qop),
106 // FIXME: If "omit" is passed, these below end up in;
107 // "Dynamic test case error: Performing a valueof or send operation on a non-specific template of type @SIPmsg_Types.GenericParam"
108 f_ts_Param_omit("cnonce", f_sip_str_quote(cnonce)),
109 f_ts_Param_omit("nc", nc)
110 }
111}
112
113template (value) Credentials ts_Credentials_OtherAuth(template (value) OtherAuth otherResponse) := {
114 otherResponse := otherResponse
115}
116
117template (value) Authorization ts_Authorization(template (value) Credentials body) := {
118 fieldName := AUTHORIZATION_E,
119 body := body
120}
121
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100122// [20.10]
123template (present) NameAddr tr_NameAddr(template (present) SipUrl addrSpec := ?,
124 template charstring displayName := *) := {
125 displayName := displayName,
126 addrSpec := addrSpec
Harald Welteb0d93602018-03-20 18:09:34 +0100127}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100128template (value) NameAddr ts_NameAddr(template (value) SipUrl addrSpec,
129 template (omit) charstring displayName := omit) := {
130 displayName := displayName,
131 addrSpec := addrSpec
132}
133
134template (present) Addr_Union tr_Addr_Union_NameAddr(template (present) NameAddr nameAddr := ?) := {
135 nameAddr := nameAddr
136}
137template (value) Addr_Union ts_Addr_Union_NameAddr(template (value) NameAddr nameAddr) := {
138 nameAddr := nameAddr
139}
140
141template (present) Addr_Union tr_Addr_Union_SipUrl(template (present) SipUrl sipUrl := ?) := {
142 addrSpecUnion := sipUrl
143}
144template (value) Addr_Union ts_Addr_Union_SipUrl(template (value) SipUrl sipUrl) := {
145 addrSpecUnion := sipUrl
146}
147
148
149template (present) ContactAddress tr_ContactAddress(template (present) Addr_Union addressField := ?,
150 template SemicolonParam_List contactParams := *) := {
151 addressField := addressField,
152 contactParams := contactParams
153}
154template (value) ContactAddress ts_ContactAddress(template (value) Addr_Union addressField,
155 template (omit) SemicolonParam_List contactParams := omit) := {
156 addressField := addressField,
157 contactParams := contactParams
158}
159
160template (present) Contact tr_Contact(template (present) ContactAddress_List contactAddresses := ?) := {
161 fieldName := CONTACT_E,
162 contactBody := {
163 contactAddresses := contactAddresses
164 }
165}
166template (value) Contact ts_Contact(template (value) ContactAddress_List contactAddresses) := {
167 fieldName := CONTACT_E,
168 contactBody := {
169 contactAddresses := contactAddresses
170 }
171}
172
173template (value) Contact ts_ContactWildcard := {
174 fieldName := CONTACT_E,
175 contactBody := {
176 wildcard := "*"
177 }
178}
179
180template (present) Contact tr_Contact_SipAddr(template (present) SipAddr contact_addr := ?)
181 := tr_Contact({ tr_ContactAddress(contact_addr.addr, contact_addr.params) });
182
183private function f_tr_Contact_SipAddr(template SipAddr contact_addr) return template Contact
184{
185 if (istemplatekind(contact_addr, "omit")) {
186 return omit;
187 } else if (istemplatekind(contact_addr, "*")) {
188 return *;
189 }
190 return tr_Contact_SipAddr(contact_addr);
191}
192
193template (value) Contact ts_Contact_SipAddr(template (value) SipAddr contact_addr)
194 := ts_Contact({ ts_ContactAddress(contact_addr.addr, contact_addr.params) });
195private function ts_Contact_SipAddr_omit(template (omit) SipAddr contact_addr := omit) return template (omit) Contact
196{
197 if (istemplatekind(contact_addr, "omit")) {
198 return omit;
199 }
200 return ts_Contact_SipAddr(contact_addr);
201}
202
203
204// [20.19]
205template (value) Expires ts_Expires(template (value) DeltaSec deltaSec := "7200") := {
206 fieldName := EXPIRES_E,
207 deltaSec := deltaSec
208}
209
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200210
211// [20.32]
212template (value) Require ts_Require(template (value) OptionTag_List optionsTags := {}) := {
213 fieldName := REQUIRE_E,
214 optionsTags := optionsTags
215}
216template (present) Require tr_Require(template (present) OptionTag_List optionsTags := ?) := {
217 fieldName := REQUIRE_E,
218 optionsTags := optionsTags
219}
220
221// [20.37]
222template (value) Supported ts_Supported(template (value) OptionTag_List optionsTags := {}) := {
223 fieldName := SUPPORTED_E,
224 optionsTags := optionsTags
225}
226template (present) Supported tr_Supported(template (present) OptionTag_List optionsTags := ?) := {
227 fieldName := SUPPORTED_E,
228 optionsTags := optionsTags
229}
230
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200231// [20.41 RFC2616 14.43]
232template (value) UserAgent ts_UserAgent(template (value) ServerVal_List userAgentBody := {}) := {
233 fieldName := USER_AGENT_E,
234 userAgentBody := userAgentBody
235}
236template (present) UserAgent tr_UserAgent(template (present) ServerVal_List userAgentBody := ?) := {
237 fieldName := USER_AGENT_E,
238 userAgentBody := userAgentBody
239}
240
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200241
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100242template (value) SipAddr ts_SipAddr(template (value) HostPort host_port,
243 template (omit) UserInfo user_info := omit,
244 template (omit) charstring displayName := omit,
245 template (omit) SemicolonParam_List params := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100246 addr := {
247 nameAddr := {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100248 displayName := displayName,
249 addrSpec := ts_SipUrl(host_port, user_info)
Harald Welteb0d93602018-03-20 18:09:34 +0100250 }
251 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100252 params := params
253}
254template (present) SipAddr tr_SipAddr(template (present) HostPort host_port := ?,
255 template UserInfo user_info := *,
256 template charstring displayName := *,
257 template SemicolonParam_List params := *) := {
258 addr := {
259 nameAddr := {
260 displayName := displayName,
261 addrSpec := tr_SipUrl(host_port, user_info)
262 }
263 },
264 params := params
Harald Welteb0d93602018-03-20 18:09:34 +0100265}
266
267/* build a receive template from a value: substitute '*' for omit */
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200268function tr_SipUrl_from_val(template (value) SipUrl tin) return template (present) SipUrl {
269 var template (present) SipUrl ret := tin;
270
271 /* if the port number is 5060, it may be omitted */
272 if (ispresent(tin.hostPort.portField) and
273 valueof(tin.hostPort.portField) == 5060) {
274 ret.hostPort.portField := 5060 ifpresent;
275 }
276 if (not ispresent(tin.userInfo.password)) {
277 ret.userInfo.password := *;
278 }
279
280 return ret;
281}
282function tr_SipAddr_from_val(template (value) SipAddr tin) return template (present) SipAddr {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100283 var template (present) SipAddr ret := tin;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200284
285 if (not ispresent(tin.addr.nameAddr.displayName)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100286 ret.addr.nameAddr.displayName := *;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200287 } else if (f_str_tolower(f_sip_str_unquote(tin.addr.nameAddr.displayName)) == "anonymous") {
288 /* if the user is Anonymous, it may be omitted */
289 ret.addr.nameAddr.displayName := tin.addr.nameAddr.displayName ifpresent;
Harald Welteb0d93602018-03-20 18:09:34 +0100290 }
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200291
292 ret.addr.nameAddr.addrSpec := tr_SipUrl_from_val(tin.addr.nameAddr.addrSpec);
293
294 if (not ispresent(tin.params)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100295 ret.params := *;
296 }
297 return ret;
298}
299
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200300function ts_SipAddr_from_Addr_Union(template (value) Addr_Union au,
301 template (omit) SemicolonParam_List params := omit)
302return template (value) SipAddr {
303 var template (value) SipUrl addrSpec := ts_SipUrl_from_Addr_Union(au);
304 var template (omit) charstring displayName;
305
306 if (ischosen(au.nameAddr)) {
307 displayName := au.nameAddr.displayName;
308 } else { /* au.addrSpecUnion */
309 displayName := omit
310 }
311
312 return ts_SipAddr(addrSpec.hostPort,
313 addrSpec.userInfo,
314 displayName,
315 params);
316}
317
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100318template (value) HostPort ts_HostPort(template (omit) charstring host := omit,
319 template (omit) integer portField := omit) := {
320 host := host,
321 portField := portField
322}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200323
324template (present) HostPort tr_HostPort(template charstring host := *,
325 template integer portField := *) := {
326 host := host,
327 portField := portField
328}
329function f_tr_HostPort(template charstring host := *,
330 template integer portField := *)
331return template (present) HostPort {
332 return f_tr_HostPort_opt_defport(tr_HostPort(host, portField));
333}
334function f_tr_HostPort_opt_defport(template (present) HostPort hp) return template (present) HostPort {
335 var template (present) HostPort hpout := hp;
Harald Welteb0d93602018-03-20 18:09:34 +0100336 /* if the port number is 5060, it may be omitted */
337 if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
338 hpout.portField := 5060 ifpresent;
339 }
340 return hpout;
341}
342
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200343function f_tr_SipUrl_opt_defport(template (present) SipUrl url) return template (present) SipUrl {
344 var template (present) SipUrl urlout := url;
345 urlout.hostPort := f_tr_HostPort_opt_defport(url.hostPort);
346 return urlout;
347}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100348
349template (value) UserInfo ts_UserInfo(template (value) charstring userOrTelephoneSubscriber,
350 template (omit) charstring password := omit) := {
351 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
352 password := password
353}
354template (present) UserInfo tr_UserInfo(template (present) charstring userOrTelephoneSubscriber := ?,
355 template charstring password := *) := {
356 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
357 password := password
358}
359
360template (value) RequestLine ts_SIP_ReqLine(Method method,
361 template (value) SipUrl uri,
Harald Welteb0d93602018-03-20 18:09:34 +0100362 charstring ver := c_SIP_VERSION) := {
363 method := method,
364 requestUri := uri,
365 sipVersion := ver
366}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100367template (present) RequestLine tr_SIP_ReqLine(template (present) Method method := ?,
368 template (present) SipUrl uri := ?,
369 template (present) charstring ver := c_SIP_VERSION) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100370 method := method,
371 requestUri := uri,
372 sipVersion := ver
373}
374
375template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := {
376 sipVersion := "SIP/2.0",
377 statusCode := status_code,
378 reasonPhrase := reason
379}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100380template (present) StatusLine tr_SIP_StatusLine(template integer status_code,
381 template charstring reason) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100382 sipVersion := "SIP/2.0",
383 statusCode := status_code,
384 reasonPhrase := reason
385}
386
387
388template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := {
389 requestLine := rl,
390 msgHeader := c_SIP_msgHeader_empty,
391 messageBody := omit,
392 payload := omit
393}
394
395const Method_List c_SIP_defaultMethods := {
396 "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE",
397 "NOTIFY", "REFER", "UPDATE" };
398
399private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body)
400return template (omit) ContentType {
401 /* if user explicitly stated no content type */
402 if (istemplatekind(ct, "omit")) {
403 return omit;
404 }
405 /* if there's no body, then there's no content-type either */
406 if (istemplatekind(body, "omit")) {
407 return omit;
408 }
409 return ct;
410}
411
412template (value) ContentType ts_CT_SDP := {
413 fieldName := CONTENT_TYPE_E,
414 mediaType := "application/sdp"
415};
416
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200417template (value) Via ts_Via_from(template (value) HostPort addr,
418 template (value) charstring transport := "UDP") := {
Harald Welteb0d93602018-03-20 18:09:34 +0100419 fieldName := VIA_E,
420 viaBody := {
421 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200422 sentProtocol := { "SIP", "2.0", transport },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100423 sentBy := addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100424 viaParams := omit
425 }
426 }
427}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100428template (present) Via tr_Via_from(template (present) HostPort host_port := ?,
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200429 template (present) charstring transport := ?,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100430 template SemicolonParam_List viaParams := *) := {
431 fieldName := VIA_E,
432 viaBody := {
433 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200434 sentProtocol := { "SIP", "2.0", ? },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100435 sentBy := host_port,
436 viaParams := viaParams
437 }
438 }
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200439}
440
441template (present) OtherAuth
442tr_OtherAuth(template (present) charstring authScheme := ?,
443 template (present) CommaParam_List authParams := ?) := {
444 authScheme := authScheme,
445 authParams := authParams
446}
447
448template (value) OtherAuth
449ts_OtherAuth(template (value) charstring authScheme,
450 template (value) CommaParam_List authParams) := {
451 authScheme := authScheme,
452 authParams := authParams
453}
454
455template (present) Challenge
456tr_Challenge_digestCln(template (present) CommaParam_List digestCln := ?) := {
457 digestCln := digestCln
458}
459
460template (value) Challenge
461ts_Challenge_digestCln(template (value) CommaParam_List digestCln) := {
462 digestCln := digestCln
463}
464
465template (present) Challenge
466tr_Challenge_otherChallenge(template (present) OtherAuth otherChallenge := ?) := {
467 otherChallenge := otherChallenge
468}
469
470template (value) Challenge
471ts_Challenge_otherChallenge(template (value) OtherAuth otherChallenge) := {
472 otherChallenge := otherChallenge
473}
474
475template (present) WwwAuthenticate
476tr_WwwAuthenticate(template (present) Challenge_list challenge := ?) := {
477 fieldName := WWW_AUTHENTICATE_E,
478 challenge := challenge
479}
480
481template (value) WwwAuthenticate
482ts_WwwAuthenticate(template (value) Challenge_list challenge) := {
483 fieldName := WWW_AUTHENTICATE_E,
484 challenge := challenge
485}
Harald Welteb0d93602018-03-20 18:09:34 +0100486
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200487// RFC3329
488template (present) Security_client
489tr_Security_client(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
490 fieldName := SECURITY_CLIENT_E,
491 sec_mechanism_list := sec_mechanism_list
492}
493template (value) Security_client
494ts_Security_client(template (value) Security_mechanism_list sec_mechanism_list) := {
495 fieldName := SECURITY_CLIENT_E,
496 sec_mechanism_list := sec_mechanism_list
497}
498
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200499template (present) Security_server
500tr_Security_server(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
501 fieldName := SECURITY_SERVER_E,
502 sec_mechanism_list := sec_mechanism_list
503}
504template (value) Security_server
505ts_Security_server(template (value) Security_mechanism_list sec_mechanism_list) := {
506 fieldName := SECURITY_SERVER_E,
507 sec_mechanism_list := sec_mechanism_list
508}
509
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200510template (present) Security_mechanism
511tr_Security_mechanism(template (present) charstring name := ?,
512 template SemicolonParam_List params := *) := {
513 mechanism_name := name,
514 mechanism_params := params
515}
516template (value) Security_mechanism
517ts_Security_mechanism(template (value) charstring name,
518 template (omit) SemicolonParam_List params := omit) := {
519 mechanism_name := name,
520 mechanism_params := params
521}
522
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100523template (value) MessageHeader ts_SIP_msgHeader_empty := c_SIP_msgHeader_empty;
524template (value) MessageHeader
525ts_SIP_msgh_std(template (value) CallidString call_id,
526 template (value) SipAddr from_addr,
527 template (value) SipAddr to_addr,
528 template (omit) Contact contact,
529 template (value) charstring method,
530 template (value) integer seq_nr,
531 template (value) Via via,
532 template (omit) ContentType content_type := omit,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200533 template (omit)Authorization authorization := omit,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200534 template (omit) Allow allow := ts_Allow(c_SIP_defaultMethods),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200535 template (omit) Expires expires := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200536 template (omit) Require require := omit,
537 template (omit) Security_client security_client := omit,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200538 template (omit) Security_server security_server := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200539 template (omit) Supported supported := omit,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200540 template (omit) UserAgent userAgent := ts_UserAgent({ "osmo-ttcn3-hacks/0.23" }),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200541 template (omit) WwwAuthenticate wwwAuthenticate := omit
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100542 ) modifies ts_SIP_msgHeader_empty := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200543 allow := allow,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200544 authorization := authorization,
Harald Welteb0d93602018-03-20 18:09:34 +0100545 callId := {
546 fieldName := CALL_ID_E,
547 callid := call_id
548 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100549 contact := contact,
Harald Welteb0d93602018-03-20 18:09:34 +0100550 contentType := content_type,
551 cSeq := {
552 fieldName := CSEQ_E,
553 seqNumber := seq_nr,
554 method := method
555 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100556 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100557 fromField := {
558 fieldName := FROM_E,
559 addressField := from_addr.addr,
560 fromParams := from_addr.params
561 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200562 require := require,
563 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200564 security_server := security_server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200565 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100566 toField := {
567 fieldName := TO_E,
568 addressField := to_addr.addr,
569 toParams := to_addr.params
570 },
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200571 userAgent := userAgent,
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200572 via := via,
573 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100574}
575
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100576template (present) MessageHeader
577tr_SIP_msgh_std(template CallidString call_id,
578 template SipAddr from_addr,
579 template SipAddr to_addr,
580 template Contact contact,
581 template (present) Via via := tr_Via_from(?),
582 template charstring method,
583 template ContentType content_type := *,
584 template integer seq_nr := ?,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200585 template Allow allow := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200586 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200587 template Require require := *,
588 template Security_client security_client := *,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200589 template Security_server security_server := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200590 template Supported supported := *,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200591 template UserAgent userAgent := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200592 template WwwAuthenticate wwwAuthenticate := *
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100593 ) modifies t_SIP_msgHeader_any := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200594 allow := allow,
Harald Welteb0d93602018-03-20 18:09:34 +0100595 callId := {
596 fieldName := CALL_ID_E,
597 callid := call_id
598 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100599 contact := contact,
Harald Welteb0d93602018-03-20 18:09:34 +0100600 contentType := content_type,
601 cSeq := {
602 fieldName := CSEQ_E,
603 seqNumber := seq_nr,
604 method := method
605 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100606 expires := expires,
Harald Welteb0d93602018-03-20 18:09:34 +0100607 fromField := {
608 fieldName := FROM_E,
609 addressField := from_addr.addr,
610 fromParams := from_addr.params
611 },
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200612 require := require,
613 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200614 security_server := security_server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200615 supported := supported,
Harald Welteb0d93602018-03-20 18:09:34 +0100616 toField := {
617 fieldName := TO_E,
618 addressField := to_addr.addr,
619 toParams := to_addr.params
620 },
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200621 userAgent := userAgent,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200622 via := via,
623 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100624}
625
626
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100627template (value) PDU_SIP_Request
628ts_SIP_REGISTER(template (value) SipUrl sip_url_host_port,
629 template (value) CallidString call_id,
630 template (value) SipAddr from_addr,
631 template (value) SipAddr to_addr,
632 template (value) Via via,
633 integer seq_nr,
634 template (omit) Contact contact,
635 template (omit) Expires expires,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200636 template (omit) Authorization authorization := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200637 template (omit) Require require := omit,
638 template (omit) Security_client security_client := omit,
639 template (omit) Supported supported := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100640 template (omit) charstring body := omit) := {
641 requestLine := ts_SIP_ReqLine(REGISTER_E, sip_url_host_port),
642 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
643 "REGISTER", seq_nr, via,
644 f_ContentTypeOrOmit(ts_CT_SDP, body),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200645 authorization := authorization,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200646 expires := expires,
647 require := require,
648 security_client := security_client,
649 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100650 messageBody := body,
651 payload := omit
652}
653template (present) PDU_SIP_Request
654tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?,
655 template (present) CallidString call_id := ?,
656 template (present) SipAddr from_addr := ?,
657 template (present) SipAddr to_addr := ?,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200658 template (present) Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100659 template integer seq_nr := *,
660 template Contact contact := *,
661 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200662 template Require require := *,
663 template Security_client security_client := *,
664 template Supported supported := *,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100665 template charstring body := *) := {
666 requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port),
667 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200668 via, "REGISTER", *, seq_nr,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200669 expires := expires,
670 require := require,
671 security_client := security_client,
672 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100673 messageBody := body,
674 payload := omit
675}
676
677template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200678ts_SIP_INVITE(template (value) CallidString call_id,
679 template (value) SipAddr from_addr,
680 template (value) SipAddr to_addr,
681 template (value) Via via,
682 template (value) Contact contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100683 integer seq_nr,
684 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100685 requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200686 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100687 "INVITE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200688 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100689 f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100690 messageBody := body,
691 payload := omit
692}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100693template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200694tr_SIP_INVITE(template (present) SipUrl uri,
695 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100696 template SipAddr from_addr,
697 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200698 template Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100699 template integer seq_nr,
700 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200701 requestLine := tr_SIP_ReqLine(INVITE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100702 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200703 via, "INVITE", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100704 messageBody := body,
705 payload := omit
706}
707
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100708template (value) PDU_SIP_Request
709ts_SIP_BYE(CallidString call_id,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200710 template (value) SipAddr from_addr,
711 template (value) SipAddr to_addr,
712 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100713 integer seq_nr,
714 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100715 requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec),
716 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200717 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100718 messageBody := body,
719 payload := omit
720}
721
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100722template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200723tr_SIP_BYE(template (present) SipUrl uri,
724 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100725 template SipAddr from_addr,
726 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200727 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100728 template integer seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200729 template charstring body := *) := {
730 requestLine := tr_SIP_ReqLine(BYE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100731 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200732 via, "BYE", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100733 messageBody := body,
734 payload := omit
735}
736
737
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100738template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200739ts_SIP_ACK(template (value) CallidString call_id,
740 template (value) SipAddr from_addr,
741 template (value) SipAddr to_addr,
742 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100743 integer seq_nr,
744 template (omit) charstring body) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100745 requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100746 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr,
747 ts_Contact_SipAddr(from_addr),
748 "ACK", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200749 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100750 f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100751 messageBody := body,
752 payload := omit
753}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100754template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200755tr_SIP_ACK(template (present) SipUrl uri,
756 template CallidString call_id,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100757 template SipAddr from_addr,
758 template SipAddr to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200759 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100760 template integer seq_nr,
761 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200762 requestLine := tr_SIP_ReqLine(ACK_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100763 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200764 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100765 "ACK", *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100766 messageBody := body,
767 payload := omit
768}
769
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200770template (present) PDU_SIP_Request
771tr_SIP_CANCEL(template (present) SipUrl uri,
772 template (present) CallidString call_id,
773 template (present) SipAddr from_addr,
774 template (present) SipAddr to_addr,
775 template (present) Via via,
776 template (present) integer seq_nr,
777 template charstring body := *) := {
778 requestLine := tr_SIP_ReqLine(CANCEL_E, uri),
779 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
780 via,
781 "CANCEL", *, seq_nr),
782 messageBody := body,
783 payload := omit
784}
785
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100786template (value) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200787ts_SIP_Response(template (value) CallidString call_id,
788 template (value) SipAddr from_addr,
789 template (value) SipAddr to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100790 charstring method,
791 integer status_code,
792 integer seq_nr,
793 charstring reason,
794 Via via,
795 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100796 statusLine := ts_SIP_StatusLine(status_code, reason),
797 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
798 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
799 messageBody := body,
800 payload := omit
801}
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +0200802/* 100 Trying */
803template (value) PDU_SIP_Response
804ts_SIP_Response_Trying(
805 template (value) CallidString call_id,
806 template (value) SipAddr from_addr,
807 template (value) SipAddr to_addr,
808 Via via,
809 integer seq_nr,
810 charstring method := "INVITE",
811 template (omit) charstring body := omit) := {
812 statusLine := ts_SIP_StatusLine(100, "Trying"),
813 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
814 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
815 messageBody := body,
816 payload := omit
817}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200818/* 180 Ringing */
819template (value) PDU_SIP_Response
820ts_SIP_Response_Ringing(
821 template (value) CallidString call_id,
822 template (value) SipAddr from_addr,
823 template (value) SipAddr to_addr,
824 Via via,
825 integer seq_nr,
826 charstring method := "INVITE",
827 template (omit) charstring body := omit) := {
828 statusLine := ts_SIP_StatusLine(180, "Ringing"),
829 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
830 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
831 messageBody := body,
832 payload := omit
833}
834
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100835template (present) PDU_SIP_Response
836tr_SIP_Response(template CallidString call_id,
837 template SipAddr from_addr,
838 template SipAddr to_addr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200839 template (present) Via via := tr_Via_from(?),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100840 template Contact contact,
841 template charstring method,
842 template integer status_code,
843 template integer seq_nr := ?,
844 template charstring reason := ?,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200845 template charstring body := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100846 statusLine := tr_SIP_StatusLine(status_code, reason),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100847 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200848 via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100849 method, *, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100850 messageBody := body,
851 payload := omit
852}
853
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200854/* Expect during first REGISTER/INVITE/... when authorization is required: */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100855template (present) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200856tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100857 template CallidString call_id,
858 template SipAddr from_addr,
859 template SipAddr to_addr,
860 template (present) Via via := tr_Via_from(?),
861 template Contact contact := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200862 template (present) WwwAuthenticate wwwAuthenticate := ?,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100863 template integer seq_nr := ?,
864 template charstring method := "REGISTER",
865 template integer status_code := 401,
866 template charstring reason := "Unauthorized",
867 template charstring body := *) := {
868 statusLine := tr_SIP_StatusLine(status_code, reason),
869 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
870 via,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200871 method, *, seq_nr,
872 wwwAuthenticate := wwwAuthenticate),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +0100873 messageBody := body,
874 payload := omit
875}
Harald Welteb0d93602018-03-20 18:09:34 +0100876
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200877/* 100 Trying */
878template (present) PDU_SIP_Response
879tr_SIP_Response_Trying(
880 template CallidString call_id,
881 template SipAddr from_addr,
882 template SipAddr to_addr,
883 template (present) Via via := tr_Via_from(?),
884 template integer seq_nr := ?,
885 template charstring method := "INVITE",
886 template integer status_code := 100,
887 template charstring reason := "Trying",
888 template charstring body := *) := {
889 statusLine := tr_SIP_StatusLine(status_code, reason),
890 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
891 via,
892 method, *, seq_nr),
893 messageBody := body,
894 payload := omit
895}
896
897/* 180 Ringing */
898template (present) PDU_SIP_Response
899tr_SIP_Response_Ringing(
900 template CallidString call_id,
901 template SipAddr from_addr,
902 template SipAddr to_addr,
903 template (present) Via via := tr_Via_from(?),
904 template integer seq_nr := ?,
905 template charstring method := "INVITE",
906 template integer status_code := 180,
907 template charstring reason := "Ringing",
908 template charstring body := *) := {
909 statusLine := tr_SIP_StatusLine(status_code, reason),
910 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
911 via,
912 method, *, seq_nr),
913 messageBody := body,
914 payload := omit
915}
916
917/****************
918 * FUNCTIONS:
919 ****************/
920
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200921function f_sip_param_find(GenericParam_List li,
922 template (present) charstring id := ?)
923return template (omit) GenericParam {
924 var integer i;
925
926 for (i := 0; i < lengthof(li); i := i + 1) {
927 if (not ispresent(li[i])) {
928 continue;
929 }
930 if (match(li[i].id, id)) {
931 return li[i];
932 }
933 }
934 return omit;
935}
936
937function f_sip_param_find_or_fail(GenericParam_List li,
938 template (present) charstring id := ?)
939return GenericParam {
940 var template (omit) GenericParam parameter;
941 parameter := f_sip_param_find(li, id);
942 if (istemplatekind(parameter, "omit")) {
943 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
944 log2str("Param ", id, " not found in ", li));
945 }
946 return valueof(parameter);
947}
948
949function f_sip_param_get_value(GenericParam_List li,
950 template (present) charstring id := ?)
951return template (omit) charstring {
952 var template (omit) GenericParam parameter;
953 parameter := f_sip_param_find(li, id);
954 if (istemplatekind(parameter, "omit")) {
955 return omit;
956 }
957 return parameter.paramValue;
958}
959
960function f_sip_param_get_value_or_fail(GenericParam_List li,
961 template (present) charstring id := ?)
962return template (omit) charstring {
963 var GenericParam parameter;
964 parameter := f_sip_param_find_or_fail(li, id);
965 return parameter.paramValue;
966}
967
968function f_sip_param_get_value_present_or_fail(GenericParam_List li,
969 template (present) charstring id := ?)
970return charstring {
971 var GenericParam parameter;
972 parameter := f_sip_param_find_or_fail(li, id);
973 if (not ispresent(parameter.paramValue)) {
974 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
975 log2str("Param ", id, " value not present in ", li));
976 }
977 return parameter.paramValue;
978}
979
980function f_sip_param_match_value(GenericParam_List li,
981 template (present) charstring id := ?,
982 template charstring exp_paramValue := *)
983return boolean {
984 var template (omit) charstring val;
985 val := f_sip_param_get_value_or_fail(li, id);
986 if (istemplatekind(val, "omit")) {
987 return istemplatekind(val, "omit") or istemplatekind(val, "*");
988 }
989 return match(valueof(val), exp_paramValue);
990}
991
992function f_sip_param_match_value_or_fail(GenericParam_List li,
993 template (present) charstring id := ?,
994 template charstring exp_paramValue := *)
995{
996 var template (omit) charstring val := f_sip_param_get_value_or_fail(li, id);
997 if (istemplatekind(val, "omit")) {
998 if (istemplatekind(val, "omit") or istemplatekind(val, "*")) {
999 return;
1000 } else {
1001 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1002 log2str("Param ", id, " match failed: val ", val,
1003 " vs exp ", exp_paramValue));
1004 }
1005 }
1006 if (not match(valueof(val), exp_paramValue)) {
1007 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1008 log2str("Param ", id, " match failed: val ", val,
1009 " vs exp ", exp_paramValue));
1010 }
1011}
1012
1013function f_sip_param_remove(template (omit) GenericParam_List li_tpl, charstring id)
1014return GenericParam_List {
1015 var integer i;
1016 var GenericParam_List li;
1017 var GenericParam_List new_li := {};
1018
1019 if (istemplatekind(li_tpl, "omit")) {
1020 return {};
1021 }
1022
1023 li := valueof(li_tpl);
1024 for (i := 0; i < lengthof(li); i := i + 1) {
1025 if (not ispresent(li[i]) or
1026 not match(li[i].id, id)) {
1027 new_li := new_li & {li[i]};
1028 }
1029 }
1030 return new_li;
1031}
1032
1033function f_sip_param_set(template (omit) GenericParam_List li_tpl, charstring id, charstring val)
1034return GenericParam_List {
1035 var integer i;
1036 var GenericParam_List li;
1037 var GenericParam_List new_li := {};
1038 var boolean found := false;
1039
1040 if (istemplatekind(li_tpl, "omit")) {
1041 return { valueof(ts_Param(id, val)) };
1042 }
1043
1044 li := valueof(li_tpl);
1045 for (i := 0; i < lengthof(li); i := i + 1) {
1046 if (not ispresent(li[i]) or
1047 not match(li[i].id, id)) {
1048 new_li := new_li & {li[i]};
1049 continue;
1050 }
1051 new_li := new_li & { valueof(ts_Param(li[i].id, val)) };
1052 found := true;
1053 }
1054
1055 if (not found) {
1056 new_li := new_li & { valueof(ts_Param(id, val)) };
1057 }
1058 return new_li;
1059}
1060
1061/* Make sure string is quoted. */
1062function f_sip_str_quote(template (value) charstring val) return charstring {
1063 var charstring str := valueof(val);
1064 if (lengthof(str) == 0) {
1065 return "";
1066 }
1067
1068 if (str[0] != "\"") {
1069 return "\"" & str & "\"";
1070 }
1071 return str;
1072}
1073
1074/* Make sure string is unquoted.
1075 * Similar to unq() in RFC 2617 */
1076function f_sip_str_unquote(template (value) charstring val) return charstring {
1077 var charstring str := valueof(val);
1078 var integer len := lengthof(str);
1079
1080 if (len <= 1) {
1081 return str;
1082 }
1083
1084 if (str[0] == "\"" and str[len - 1] == "\"") {
1085 return substr(str, 1, len - 2);
1086 }
1087 return str;
1088}
1089
1090/* RFC 2617 3.2.2.2 A1 */
1091function f_sip_digest_A1(charstring user, charstring realm, charstring password) return charstring {
1092
1093 /* RFC 2617 3.2.2.2 A1 */
1094 var charstring A1 := f_sip_str_unquote(user) & ":" &
1095 f_sip_str_unquote(realm) & ":" &
1096 password;
1097 var charstring digestA1 := f_str_tolower(f_calculateMD5(A1));
1098 log("A1: md5('", A1, "') = ", digestA1);
1099 return digestA1;
1100}
1101
1102/* RFC 2617 3.2.2.2 A2 */
1103function f_sip_digest_A2(charstring method, charstring uri) return charstring {
1104
1105 var charstring A2 := method & ":" & uri
1106 var charstring digestA2 := f_str_tolower(f_calculateMD5(A2));
1107 log("A2: md5('", A2, "') = ", digestA2);
1108 return digestA2;
1109}
1110
1111/* RFC 2617 3.2.2.1 Request-Digest */
1112function f_sip_digest_RequestDigest(charstring digestA1, charstring nonce,
1113 charstring nc, charstring cnonce,
1114 charstring qop, charstring digestA2) return charstring {
1115 var charstring digest_data := f_sip_str_unquote(nonce) & ":" &
1116 nc & ":" &
1117 cnonce & ":" &
1118 f_sip_str_unquote(qop) & ":" &
1119 digestA2;
1120 var charstring req_digest := f_sip_digest_KD(digestA1, digest_data);
1121 log("Request-Digest: md5('", digestA1, ":", digest_data ,"') = ", req_digest);
1122 return req_digest;
1123}
1124
1125/* RFC 2617 3.2.1 The WWW-Authenticate Response Header
1126 * KD(secret, data) = H(concat(secret, ":", data))
1127 */
1128function f_sip_digest_KD(charstring secret, charstring data) return charstring {
1129 return f_str_tolower(f_calculateMD5(secret & ":" & data));
1130}
1131
1132/* Digest Auth: RFC 2617 */
1133function f_sip_digest_gen_Authorization(WwwAuthenticate www_authenticate,
1134 charstring user, charstring password,
1135 charstring method, charstring uri,
1136 charstring cnonce := "0a4f113b", integer nc_int := 1) return Authorization {
1137 var CommaParam_List digestCln;
1138 var template (value) Authorization authorization;
1139 var template (value) Credentials cred;
1140 var template (omit) GenericParam rx_param;
1141
1142 digestCln := www_authenticate.challenge[0].digestCln;
1143
1144 var charstring algorithm;
1145 rx_param := f_sip_param_find(digestCln, "algorithm");
1146 if (istemplatekind(rx_param, "omit")) {
1147 /* Assume MD5 if not set */
1148 algorithm := "MD5"
1149 } else {
1150 algorithm := valueof(rx_param.paramValue);
1151 if (f_strstr(algorithm, "MD5") == -1) {
1152 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1153 log2str("Unexpected algorithm: ", algorithm));
1154 }
1155 }
1156
1157 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
1158 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
1159 var charstring opaque := f_sip_param_get_value_present_or_fail(digestCln, "opaque");
1160 var charstring qop := f_sip_param_get_value_present_or_fail(digestCln, "qop");
1161
1162 if (f_strstr(qop, "auth") == -1) {
1163 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
1164 }
1165 var charstring selected_qop := "auth";
1166
1167 /* RFC 2617 3.2.2.2 A1 */
1168 var charstring digestA1 := f_sip_digest_A1(user, realm, password);
1169 /* RFC 2617 3.2.2.3 A2 */
1170 var charstring digestA2 := f_sip_digest_A2(method, uri);
1171
1172 /* RFC 2617 3.2.2.1 Request-Digest */
1173 var charstring nc := f_str_tolower(hex2str(int2hex(nc_int, 8)));
1174 var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
1175 nc, cnonce,
1176 selected_qop, digestA2);
1177
1178 cred := ts_Credentials_DigestResponseMD5(user, realm, nonce,
1179 uri, req_digest,
1180 opaque, algorithm, selected_qop, cnonce, nc);
1181
1182 authorization := ts_Authorization(cred);
1183 return valueof(authorization);
1184}
1185
1186/* RFC 2617 3.5 Example */
1187function f_sip_digest_selftest() {
1188/*
1189The following example assumes that an access-protected document is
1190being requested from the server via a GET request. The URI of the
1191document is "http://www.nowhere.org/dir/index.html". Both client and
1192server know that the username for this document is "Mufasa", and the
1193password is "Circle Of Life" (with one space between each of the
1194three words).
1195
1196HTTP/1.1 401 Unauthorized
1197WWW-Authenticate: Digest
1198 realm="testrealm@host.com",
1199 qop="auth,auth-int",
1200 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1201 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1202
1203Authorization: Digest username="Mufasa",
1204 realm="testrealm@host.com",
1205 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1206 uri="/dir/index.html",
1207 qop=auth,
1208 nc=00000001,
1209 cnonce="0a4f113b",
1210 response="6629fae49393a05397450978507c4ef1",
1211 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1212*/
1213 var template (value) CommaParam_List digestCln := {
1214 ts_Param("realm", f_sip_str_quote("testrealm@host.com")),
1215 ts_Param("qop", f_sip_str_quote("auth,auth-int")),
1216 ts_Param("nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093")),
1217 ts_Param("opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"))
1218 };
1219 var template (value) WwwAuthenticate www_authenticate :=
1220 ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
1221
1222 var Authorization authorization :=
1223 f_sip_digest_gen_Authorization(valueof(www_authenticate),
1224 "Mufasa",
1225 "Circle Of Life",
1226 "GET",
1227 "/dir/index.html",
1228 cnonce := "0a4f113b",
1229 nc_int := 1);
1230
1231 var CommaParam_List digestResp := authorization.body.digestResponse;
1232 f_sip_param_match_value_or_fail(digestResp, "realm", f_sip_str_quote("testrealm@host.com"));
1233 f_sip_param_match_value_or_fail(digestResp, "nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093"));
1234 f_sip_param_match_value_or_fail(digestResp, "uri", f_sip_str_quote("/dir/index.html"));
1235 f_sip_param_match_value_or_fail(digestResp, "qop", "auth");
1236 f_sip_param_match_value_or_fail(digestResp, "nc", "00000001");
1237 f_sip_param_match_value_or_fail(digestResp, "cnonce", f_sip_str_quote("0a4f113b"));
1238 f_sip_param_match_value_or_fail(digestResp, "response", f_sip_str_quote("6629fae49393a05397450978507c4ef1"));
1239 f_sip_param_match_value_or_fail(digestResp, "opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"));
1240}
1241
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01001242/* RFC 3261 8.1.1.5:
1243 * "The sequence number value MUST be expressible as a 32-bit unsigned integer
1244 * and MUST be less than 2**31."
1245 */
1246function f_sip_rand_seq_nr() return integer {
1247 /* 2**31 = 2147483648 */
1248 return f_rnd_int(2147483648)
1249}
Harald Welteb0d93602018-03-20 18:09:34 +01001250
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001251function f_sip_next_seq_nr(integer seq_nr) return integer {
1252 return (seq_nr + 1) mod 2147483648;
1253}
1254
1255function f_sip_Request_inc_seq_nr(inout template (value) PDU_SIP_Request req) {
1256 req.msgHeader.cSeq.seqNumber := f_sip_next_seq_nr(valueof(req.msgHeader.cSeq.seqNumber));
1257}
1258
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001259function f_sip_rand_tag() return charstring {
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001260 /* Tags shall have at least 32 bit of randomness */
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001261 var integer rnd_int := f_rnd_int(4294967296);
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001262 /* Make collisions harder by appending time to the final string: */
1263 var integer ts_int := f_time_ms() mod 4294967296;
1264 return hex2str(int2hex(rnd_int, 8)) & "-" & hex2str(int2hex(ts_int, 8));
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001265}
1266
1267/* Generate a "branch" tag value.
1268 * RFC 3261 p.105 section 8:
1269 * "A common way to create this value is to compute a
1270 * cryptographic hash of the To tag, From tag, Call-ID header
1271 * field, the Request-URI of the request received (before
1272 * translation), the topmost Via header, and the sequence number
1273 * from the CSeq header field, in addition to any Proxy-Require
1274 * and Proxy-Authorization header fields that may be present. The
1275 * algorithm used to compute the hash is implementation-dependent,
1276 * but MD5 (RFC 1321 [35]),expressed in hexadecimal, is a reasonable
1277 * choice."
1278 * See also Section 8.1.1.7:
1279 * "The branch ID inserted by an element compliant with this
1280 * specification MUST always begin with the characters "z9hG4bK"."
1281 */
1282const charstring sip_magic_cookie := "z9hG4bK";
1283function f_sip_gen_branch(charstring tag_to,
1284 charstring tag_from,
1285 charstring tag_call_id,
1286 integer cseq) return charstring {
1287 var charstring str := tag_to & tag_from & tag_call_id & int2str(cseq);
1288 var charstring hash := f_calculateMD5(str);
1289 var charstring branch := sip_magic_cookie & hash;
1290 return branch;
1291}
1292
1293function f_sip_HostPort_to_str(HostPort host_port) return charstring {
1294 var charstring str := "";
1295 if (ispresent(host_port.host)) {
1296 str := host_port.host;
1297 }
1298 if (ispresent(host_port.portField)) {
1299 str := str & ":" & int2str(host_port.portField);
1300 }
1301 return str;
1302}
1303
1304function f_sip_SipUrl_to_str(SipUrl uri) return charstring {
1305 var charstring str := uri.scheme & f_sip_HostPort_to_str(uri.hostPort);
1306 return str;
1307}
1308
1309function f_sip_NameAddr_to_str(NameAddr naddr) return charstring {
1310 if (ispresent(naddr.displayName)) {
1311 return naddr.displayName & " <" & f_sip_SipUrl_to_str(naddr.addrSpec) & ">";
1312 } else {
1313 return f_sip_SipUrl_to_str(naddr.addrSpec);
1314 }
1315}
1316
1317function f_sip_SipAddr_to_str(SipAddr sip_addr) return charstring {
1318 if (ischosen(sip_addr.addr.nameAddr)) {
1319 return f_sip_NameAddr_to_str(sip_addr.addr.nameAddr);
1320 } else {
1321 return f_sip_SipUrl_to_str(sip_addr.addr.addrSpecUnion);
1322 }
1323}
1324
Harald Welteb0d93602018-03-20 18:09:34 +01001325}