blob: f57b524397fb3fb8ca18cd720178b5ce666e18eb [file] [log] [blame]
Harald Welteb0d93602018-03-20 18:09:34 +01001module SIP_Templates {
2
3import from SIPmsg_Types all;
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01004import from Osmocom_Types all;
Harald Welteb0d93602018-03-20 18:09:34 +01005
6/* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */
7type record SipAddr {
8 Addr_Union addr,
9 SemicolonParam_List params optional
10}
11
12const charstring c_SIP_VERSION := "SIP/2.0";
13
14template (value) SipUrl ts_SipUrl(charstring user_or_tel, charstring host, integer portnr) := {
15 scheme := "sip",
16 userInfo := {
17 userOrTelephoneSubscriber := user_or_tel,
18 password := omit
19 },
20 hostPort := {
21 host := host,
22 portField := portnr
23 },
24 urlParameters := omit,
25 headers := omit
26}
27template SipUrl tr_SipUrl(template charstring user_or_tel,
28 template charstring host,
29 template integer portnr) := {
30 scheme := "sip",
31 userInfo := {
32 userOrTelephoneSubscriber := user_or_tel,
33 password := *
34 },
35 hostPort := {
36 host := host,
37 portField := portnr
38 },
39 urlParameters := *,
40 headers := *
41}
42
43template (value) SipAddr ts_SipAddr(charstring user_or_tel, charstring host, integer portnr) := {
44 addr := {
45 nameAddr := {
46 displayName := omit,
47 addrSpec := ts_SipUrl(user_or_tel, host, portnr)
48 }
49 },
50 params := omit
51}
52template SipAddr tr_SipAddr(template charstring user_or_tel,
53 template charstring host,
54 template integer portnr) := {
55 addr := {
56 nameAddr := {
57 displayName := *,
58 addrSpec := tr_SipUrl(user_or_tel, host, portnr)
59 }
60 },
61 params := *
62}
63
64/* build a receive template from a value: substitute '*' for omit */
65function tr_SipAddr_from_val(SipAddr tin) return template SipAddr {
66 var template SipAddr ret := tin;
67 if (tin.addr.nameAddr.displayName == omit) {
68 ret.addr.nameAddr.displayName := *;
69 }
70 if (tin.addr.nameAddr.addrSpec.userInfo.password == omit) {
71 ret.addr.nameAddr.addrSpec.userInfo.password := *;
72 }
73 if (tin.params == omit) {
74 ret.params := *;
75 }
76 return ret;
77}
78
79
80function tr_HostPort(template HostPort hp) return template HostPort {
81 var template HostPort hpout := hp;
82 /* if the port number is 5060, it may be omitted */
83 if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
84 hpout.portField := 5060 ifpresent;
85 }
86 return hpout;
87}
88
89template (value) RequestLine ts_SIP_ReqLine(Method method, template (value) SipUrl uri,
90 charstring ver := c_SIP_VERSION) := {
91 method := method,
92 requestUri := uri,
93 sipVersion := ver
94}
95template RequestLine tr_SIP_ReqLine(template Method method,
96 template SipUrl uri,
97 template charstring ver := c_SIP_VERSION) := {
98 method := method,
99 requestUri := uri,
100 sipVersion := ver
101}
102
103template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := {
104 sipVersion := "SIP/2.0",
105 statusCode := status_code,
106 reasonPhrase := reason
107}
108template StatusLine tr_SIP_StatusLine(template integer status_code, template charstring reason) := {
109 sipVersion := "SIP/2.0",
110 statusCode := status_code,
111 reasonPhrase := reason
112}
113
114
115template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := {
116 requestLine := rl,
117 msgHeader := c_SIP_msgHeader_empty,
118 messageBody := omit,
119 payload := omit
120}
121
122const Method_List c_SIP_defaultMethods := {
123 "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE",
124 "NOTIFY", "REFER", "UPDATE" };
125
126private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body)
127return template (omit) ContentType {
128 /* if user explicitly stated no content type */
129 if (istemplatekind(ct, "omit")) {
130 return omit;
131 }
132 /* if there's no body, then there's no content-type either */
133 if (istemplatekind(body, "omit")) {
134 return omit;
135 }
136 return ct;
137}
138
139template (value) ContentType ts_CT_SDP := {
140 fieldName := CONTENT_TYPE_E,
141 mediaType := "application/sdp"
142};
143
144template (value) Via ts_Via_from(SipAddr from_addr) := {
145 fieldName := VIA_E,
146 viaBody := {
147 {
148 sentProtocol := { "SIP", "2.0", "UDP" },
149 sentBy := from_addr.addr.nameAddr.addrSpec.hostPort,
150 viaParams := omit
151 }
152 }
153}
154
155template (value) MessageHeader ts_SIP_msgHeader_empty :=c_SIP_msgHeader_empty;
156template (value) MessageHeader ts_SIP_msgh_std( CallidString call_id,
157 SipAddr from_addr,
158 SipAddr to_addr,
159 template (omit) SipAddr contact_addr,
160 charstring method,
161 integer seq_nr,
162 template (value) Via via,
163 template (omit) ContentType content_type := omit,
164 Method_List allow_methods := c_SIP_defaultMethods
165 ) modifies ts_SIP_msgHeader_empty := {
166 allow := {
167 fieldName := ALLOW_E,
168 methods := allow_methods
169 },
170 callId := {
171 fieldName := CALL_ID_E,
172 callid := call_id
173 },
174 contact := ts_Contact(contact_addr),
175 contentType := content_type,
176 cSeq := {
177 fieldName := CSEQ_E,
178 seqNumber := seq_nr,
179 method := method
180 },
181 fromField := {
182 fieldName := FROM_E,
183 addressField := from_addr.addr,
184 fromParams := from_addr.params
185 },
186 toField := {
187 fieldName := TO_E,
188 addressField := to_addr.addr,
189 toParams := to_addr.params
190 },
191 userAgent := {
192 fieldName := USER_AGENT_E,
193 userAgentBody := {
194 "osmo-ttcn3-hacks/0.23"
195 }
196 },
197 via := via
198}
199
200private function tr_Contact(template SipAddr contact_addr) return template Contact
201{
202 if (istemplatekind(contact_addr, "omit")) {
203 return omit;
204 } else if (istemplatekind(contact_addr, "*")) {
205 return *;
206 } else if (istemplatekind(contact_addr, "?")) {
207 return ?;
208 }
209 var template Contact ret := {
210 fieldName := CONTACT_E,
211 contactBody := {
212 contactAddresses := {
213 {
214 addressField := contact_addr.addr,
215 contactParams := contact_addr.params
216 }
217 }
218 }
219 };
220 return ret;
221}
222
223private function ts_Contact(template (omit) SipAddr contact_addr) return template (omit) Contact
224{
225 if (istemplatekind(contact_addr, "omit")) {
226 return omit;
227 }
228 var template (omit) Contact ret := {
229 fieldName := CONTACT_E,
230 contactBody := {
231 contactAddresses := {
232 {
233 addressField := contact_addr.addr,
234 contactParams := contact_addr.params
235 }
236 }
237 }
238 };
239 return ret;
240}
241
242
243function tr_AllowMethods(template Method_List allow_methods) return template Allow {
244 if (istemplatekind(allow_methods, "omit")) {
245 return omit;
246 } else if (istemplatekind(allow_methods, "*")) {
247 return *;
248 } else if (istemplatekind(allow_methods, "?")) {
249 return ?;
250 }
251 var template Allow ret := {
252 fieldName := ALLOW_E,
253 methods := allow_methods
254 }
255 return ret
256}
257
258template MessageHeader tr_SIP_msgh_std( template CallidString call_id,
259 template SipAddr from_addr,
260 template SipAddr to_addr,
261 template SipAddr contact_addr,
262 template charstring method,
263 template ContentType content_type := *,
264 template integer seq_nr := ?,
265 template Method_List allow_methods := *
266 ) modifies t_SIP_msgHeader_any := {
267 allow := tr_AllowMethods(allow_methods),
268 callId := {
269 fieldName := CALL_ID_E,
270 callid := call_id
271 },
272 contact := tr_Contact(contact_addr),
273 contentType := content_type,
274 cSeq := {
275 fieldName := CSEQ_E,
276 seqNumber := seq_nr,
277 method := method
278 },
279 fromField := {
280 fieldName := FROM_E,
281 addressField := from_addr.addr,
282 fromParams := from_addr.params
283 },
284 toField := {
285 fieldName := TO_E,
286 addressField := to_addr.addr,
287 toParams := to_addr.params
288 },
289 userAgent := *,
290 via := {
291 fieldName := VIA_E,
292 viaBody := {
293 {
294 sentProtocol := { "SIP", "2.0", "UDP" },
295 sentBy := tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort),
296 viaParams := *
297 }
298 }
299 }
300}
301
302
303template (value) PDU_SIP_Request ts_SIP_INVITE( CallidString call_id,
304 SipAddr from_addr,
305 SipAddr to_addr,
306 integer seq_nr,
307 template (omit) charstring body
308 ) := {
309 requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec),
310 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "INVITE", seq_nr,
311 ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)),
312 messageBody := body,
313 payload := omit
314}
315template PDU_SIP_Request tr_SIP_INVITE( template CallidString call_id,
316 template SipAddr from_addr,
317 template SipAddr to_addr,
318 template integer seq_nr,
319 template charstring body
320 ) := {
321 requestLine := tr_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec),
322 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?, "INVITE", *, seq_nr),
323 messageBody := body,
324 payload := omit
325}
326
327template (value) PDU_SIP_Request ts_SIP_BYE( CallidString call_id,
328 SipAddr from_addr,
329 SipAddr to_addr,
330 integer seq_nr,
331 template (omit) charstring body
332 ) := {
333 requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec),
334 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr,
335 ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)),
336 messageBody := body,
337 payload := omit
338}
339
340template PDU_SIP_Request tr_SIP_BYE( template CallidString call_id,
341 template SipAddr from_addr,
342 template SipAddr to_addr,
343 template integer seq_nr,
344 template charstring body
345 ) := {
346 requestLine := tr_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec),
347 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", *, seq_nr),
348 messageBody := body,
349 payload := omit
350}
351
352
353template (value) PDU_SIP_Request ts_SIP_ACK( CallidString call_id,
354 SipAddr from_addr,
355 SipAddr to_addr,
356 integer seq_nr,
357 template (omit) charstring body
358 ) := {
359 requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec),
360 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "ACK", seq_nr,
361 ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)),
362 messageBody := body,
363 payload := omit
364}
365template PDU_SIP_Request tr_SIP_ACK( template CallidString call_id,
366 template SipAddr from_addr,
367 template SipAddr to_addr,
368 template integer seq_nr,
369 template charstring body
370 ) := {
371 requestLine := tr_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec),
372 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, "ACK", *, seq_nr),
373 messageBody := body,
374 payload := omit
375}
376
377
378
379template (value) PDU_SIP_Response ts_SIP_Response( CallidString call_id,
380 SipAddr from_addr,
381 SipAddr to_addr,
382 charstring method,
383 integer status_code,
384 integer seq_nr,
385 charstring reason,
386 Via via,
387 template (omit) charstring body := omit
388 ) := {
389 statusLine := ts_SIP_StatusLine(status_code, reason),
390 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
391 via, f_ContentTypeOrOmit(ts_CT_SDP, body)),
392 messageBody := body,
393 payload := omit
394}
395
396template PDU_SIP_Response tr_SIP_Response( template CallidString call_id,
397 template SipAddr from_addr,
398 template SipAddr to_addr,
399 template SipAddr contact_addr,
400 template charstring method,
401 template integer status_code,
402 template integer seq_nr := ?,
403 template charstring reason := ?,
404 template charstring body := ?
405 ) := {
406 statusLine := tr_SIP_StatusLine(status_code, reason),
407 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact_addr, method, *, seq_nr),
408 messageBody := body,
409 payload := omit
410}
411
412
Pau Espin Pedrol6052a342024-03-28 20:20:46 +0100413/* RFC 3261 8.1.1.5:
414 * "The sequence number value MUST be expressible as a 32-bit unsigned integer
415 * and MUST be less than 2**31."
416 */
417function f_sip_rand_seq_nr() return integer {
418 /* 2**31 = 2147483648 */
419 return f_rnd_int(2147483648)
420}
Harald Welteb0d93602018-03-20 18:09:34 +0100421
422}