blob: 13b5f049270a9ff500ab94bd8eeb89d1ead3d34a [file] [log] [blame]
Pau Espin Pedrolcaf028d2024-04-18 13:47:07 +02001/* Component implementing a SIP UA towards Asterisk
2 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11module SIP_ConnectionHandler {
12
13import from TCCOpenSecurity_Functions all;
14import from General_Types all;
15import from Osmocom_Types all;
16import from Native_Functions all;
17import from Misc_Helpers all;
18
19import from SDP_Types all;
20import from SDP_Templates all;
21
22import from SIP_Emulation all;
23import from SIPmsg_Types all;
24import from SIP_Templates all;
25
26type port Coord_PT message
27{
28 inout charstring;
29} with { extension "internal" };
30
31const charstring COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
32const charstring COORD_CMD_START := "COORD_CMD_START";
33const charstring COORD_CMD_PICKUP := "COORD_CMD_PICKUP";
34const charstring COORD_CMD_CALL_ESTABLISHED := "COORD_CMD_CALL_ESTABLISHED";
35const charstring COORD_CMD_CALL_CANCELLED := "COORD_CMD_CALL_CANCELLED";
36const charstring COORD_CMD_HANGUP := "COORD_CMD_HANGUP";
37
38type component SIPConnHdlr extends SIP_ConnHdlr {
39 var charstring g_name;
40 var SIPConnHdlrPars g_pars;
41 timer g_Tguard;
42 var PDU_SIP_Request g_rx_sip_req;
43 var PDU_SIP_Response g_rx_sip_resp;
44
45 port Coord_PT COORD;
46}
47type record of SIPConnHdlr SIPConnHdlrList;
48
49type record SIPConnHdlrPars {
50 float t_guard,
51 charstring remote_sip_host,
52 uint16_t remote_sip_port,
53 charstring user,
54 charstring display_name,
55 charstring password,
56 SipUrl registrar_sip_req_uri,
57 SipAddr registrar_sip_record,
58 CallidString registrar_sip_call_id,
59 integer registrar_sip_seq_nr,
60 Via local_via,
61 SipUrl local_sip_url_ext,
62 SipAddr local_sip_record,
63 Contact local_contact,
64 CallPars cp optional
65}
66type record of SIPConnHdlrPars SIPConnHdlrParsList;
67
68type record CallParsMT {
69 /* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
70 boolean wait_coord_cmd_pickup,
71 /* Whether to expect CANCEL instead of ACK as answer to our OK */
72 boolean exp_cancel
73}
74template (value) CallParsMT t_CallParsMT := {
75 wait_coord_cmd_pickup := false,
76 exp_cancel := false
77}
78
79type record CallPars {
80 SipAddr calling optional,
81 SipAddr called optional,
82
83 SipAddr from_addr optional,
84 SipAddr to_addr optional,
85
86 CallidString sip_call_id,
87 integer sip_seq_nr,
88 charstring sip_body optional,
89
90 charstring local_rtp_addr,
91 uint16_t local_rtp_port,
92
93 SDP_Message peer_sdp optional,
94 CallParsMT mt
95}
96
97template (value) CallPars t_CallPars(charstring local_rtp_addr,
98 uint16_t local_rtp_port := 0,
99 template (omit) SipAddr calling := omit,
100 template (omit) SipAddr called := omit) := {
101 calling := calling,
102 called := called,
103 from_addr := omit,
104 to_addr := omit,
105 sip_call_id := hex2str(f_rnd_hexstring(15)),
106 sip_seq_nr := f_sip_rand_seq_nr(),
107 sip_body := omit,
108 local_rtp_addr := local_rtp_addr,
109 local_rtp_port := local_rtp_port,
110 peer_sdp := omit,
111 mt := t_CallParsMT
112}
113
114template (value) SIPConnHdlrPars t_Pars(charstring local_sip_host,
115 uint16_t local_sip_port,
116 charstring remote_sip_host,
117 uint16_t remote_sip_port,
118 charstring user,
119 charstring display_name := "Anonymous",
120 charstring password := "secret",
121 template (omit) CallPars cp := omit) := {
122 t_guard := 30.0,
123 remote_sip_host := remote_sip_host,
124 remote_sip_port := remote_sip_port,
125 user := user,
126 display_name := f_sip_str_quote(display_name),
127 password := password,
128 registrar_sip_req_uri := valueof(ts_SipUrlHost(remote_sip_host)),
129 registrar_sip_record := ts_SipAddr(ts_HostPort(remote_sip_host),
130 ts_UserInfo(user),
131 f_sip_str_quote(display_name)),
132 registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & local_sip_host,
133 registrar_sip_seq_nr := f_sip_rand_seq_nr(),
134 local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)),
135 local_sip_url_ext := ts_SipUrl(ts_HostPort(local_sip_host, local_sip_port),
136 ts_UserInfo(user)),
137 local_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
138 ts_UserInfo(user)),
139 local_contact := valueof(ts_Contact({
140 ts_ContactAddress(
141 ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
142 local_sip_host,
143 local_sip_port),
144 ts_UserInfo(user))),
145 omit)
146 })),
147 cp := cp
148}
149
150private altstep as_Tguard() runs on SIPConnHdlr {
151 [] g_Tguard.timeout {
152 setverdict(fail, "Tguard timeout");
153 mtc.stop;
154 }
155}
156
157type function void_fn(charstring id) runs on SIPConnHdlr;
158function f_handler_init(void_fn fn, charstring id, SIPConnHdlrPars pars)
159runs on SIPConnHdlr {
160 g_name := id;
161 g_pars := pars;
162 g_Tguard.start(pars.t_guard);
163 activate(as_Tguard());
164
165 // Make sure the UA is deregistered before starting the test:
166 // sends REGISTER with Contact = "*" and Expires = 0
167 //f_SIP_deregister();
168
169 /* call the user-supied test case function */
170 fn.apply(id);
171}
172
173private function f_tr_Via_response(Via via_req) return template (present) Via {
174 template (present) SemicolonParam_List via_resp_params := ?;
175
176 /*via_resp_params := {
177 { id := "rport", paramValue := int2str(g_pars.remote_sip_port) },
178 { id := "received", paramValue := g_pars.remote_sip_host }
179 }; */
180 return tr_Via_from(via_req.viaBody[0].sentBy,
181 via_resp_params);
182}
183
184private function f_tr_To_response(template (value) SipAddr to_req) return template (present) SipAddr {
185 return tr_SipAddr_from_val(to_req);
186}
187
188private function f_tr_From(template (value) SipAddr from_req) return template (present) SipAddr {
189 return tr_SipAddr_from_val(from_req);
190}
191
192private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on SIPConnHdlr
193{
194 var PDU_SIP_Request sip_req;
195 [] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
196 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
197 log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str));
198 }
199}
200
201private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on SIPConnHdlr
202{
203 var PDU_SIP_Response sip_resp;
204 [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
205 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
206 log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str));
207 }
208}
209
210altstep as_SIP_expect_req(template (present) PDU_SIP_Request sip_expect, boolean fail_others := true) runs on SIPConnHdlr
211{
212 var charstring sip_expect_str := log2str(sip_expect);
213 [] SIP.receive(sip_expect) -> value g_rx_sip_req;
214 [fail_others] as_SIP_fail_req(sip_expect_str);
215 [fail_others] as_SIP_fail_resp(sip_expect_str);
216}
217
218altstep as_SIP_expect_resp(template (present) PDU_SIP_Response sip_expect, boolean fail_others := true) runs on SIPConnHdlr
219{
220 var charstring sip_expect_str := log2str(sip_expect);
221 [] SIP.receive(sip_expect) -> value g_rx_sip_resp;
222 [fail_others] as_SIP_fail_resp(sip_expect_str);
223 [fail_others] as_SIP_fail_req(sip_expect_str);
224}
225
226altstep as_SIP_ignore_resp(template PDU_SIP_Response sip_expect := ?) runs on SIPConnHdlr
227{
228 [] SIP.receive(sip_expect) -> value g_rx_sip_resp {
229 log("Ignoring ", g_rx_sip_resp);
230 repeat;
231 }
232}
233
234private function f_gen_sdp() runs on SIPConnHdlr return charstring {
235 var charstring sdp :=
236 "v=0\r\n" &
237 "o=0502 2390 1824 IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
238 "s=Talk\r\n" &
239 "c=IN IP4 " & g_pars.cp.local_rtp_addr & "\r\n" &
240 "t=0 0\r\n" &
241 "a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
242 "a=record:off\r\n" &
243 "m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 96 97 98 0 8 18 99 100 101\r\n" &
244 "a=rtpmap:96 opus/48000/2\r\n" &
245 "a=fmtp:96 useinbandfec=1\r\n" &
246 "a=rtpmap:97 speex/16000\r\n" &
247 "a=fmtp:97 vbr=on\r\n" &
248 "a=rtpmap:98 speex/8000\r\n" &
249 "a=fmtp:98 vbr=on\r\n" &
250 "a=fmtp:18 annexb=yes\r\n" &
251 "a=rtpmap:99 telephone-event/48000\r\n" &
252 "a=rtpmap:100 telephone-event/16000\r\n" &
253 "a=rtpmap:101 telephone-event/8000\r\n" &
254 "a=rtcp:" & int2str(g_pars.cp.local_rtp_port + 1) & "\r\n" &
255 "a=rtcp-fb:* trr-int 1000\r\n" &
256 "a=rtcp-fb:* ccm tmmbr\r\n";
257 return sdp;
258}
259
260function f_SIP_register() runs on SIPConnHdlr return PDU_SIP_Response
261{
262 var template (present) PDU_SIP_Response exp;
263 var Authorization authorization;
264 var Via via := g_pars.local_via;
265 var SipAddr from_sipaddr := g_pars.registrar_sip_record;
266 var charstring branch_value;
267
268 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
269 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
270 g_pars.registrar_sip_call_id,
271 g_pars.registrar_sip_seq_nr);
272
273 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
274 from_sipaddr.params := f_sip_param_set(from_sipaddr.params, "tag", f_sip_rand_tag());
275 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
276 g_pars.registrar_sip_call_id,
277 from_sipaddr,
278 g_pars.registrar_sip_record,
279 via,
280 g_pars.registrar_sip_seq_nr,
281 g_pars.local_contact,
282 ts_Expires("7200")));
283
284 exp := tr_SIP_Response_Unauthorized(
285 g_pars.registrar_sip_call_id,
286 from_sipaddr,
287 f_tr_To_response(g_pars.registrar_sip_record),
288 f_tr_Via_response(via),
289 *,
290 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
291 g_pars.registrar_sip_seq_nr);
292 as_SIP_expect_resp(exp);
293
294 /* Digest Auth: RFC 2617 */
295 authorization := f_sip_digest_gen_Authorization(g_rx_sip_resp.msgHeader.wwwAuthenticate,
296 g_pars.user, g_pars.password,
297 "REGISTER",
298 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
299
300 /* New transaction: */
301 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
302 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
303 f_sip_SipAddr_to_str(g_pars.registrar_sip_record),
304 g_pars.registrar_sip_call_id,
305 g_pars.registrar_sip_seq_nr);
306 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
307
308 SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_req_uri,
309 g_pars.registrar_sip_call_id,
310 from_sipaddr,
311 g_pars.registrar_sip_record,
312 via,
313 g_pars.registrar_sip_seq_nr,
314 g_pars.local_contact,
315 ts_Expires("7200"),
316 authorization := authorization));
317
318 /* Wait for OK answer */
319 exp := tr_SIP_Response(
320 g_pars.registrar_sip_call_id,
321 from_sipaddr,
322 f_tr_To_response(g_pars.registrar_sip_record),
323 f_tr_Via_response(via),
324 *,
325 "REGISTER", 200,
326 g_pars.registrar_sip_seq_nr, "OK");
327 as_SIP_expect_resp(exp);
328
329 /* Prepare for next use: */
330 g_pars.registrar_sip_seq_nr := g_pars.registrar_sip_seq_nr + 1;
331 return g_rx_sip_resp;
332}
333
334function f_SIP_mo_call_setup() runs on SIPConnHdlr
335{
336 var template (value) PDU_SIP_Request req;
337 var template (present) PDU_SIP_Response exp;
338 var Via via;
339 var charstring tx_sdp := f_gen_sdp();
340 var default d_trying, d_ringing;
341 var charstring branch_value;
342
343 /* RFC 3261 8.1.1.3 From */
344 g_pars.cp.from_addr := g_pars.cp.calling;
345 g_pars.cp.from_addr.params := f_sip_param_set(g_pars.cp.from_addr.params, "tag", f_sip_rand_tag());
346 g_pars.cp.to_addr := g_pars.cp.called;
347 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
348 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
349 g_pars.cp.sip_call_id,
350 g_pars.cp.sip_seq_nr);
351 via := g_pars.local_via;
352 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
353
354 req := ts_SIP_INVITE(g_pars.cp.sip_call_id,
355 g_pars.cp.from_addr,
356 g_pars.cp.to_addr,
357 via,
358 g_pars.local_contact,
359 g_pars.cp.sip_seq_nr,
360 body := tx_sdp);
361
362 SIP.send(req);
363
364 /* RFC 3261 22.2: */
365 exp := tr_SIP_Response_Unauthorized(
366 g_pars.cp.sip_call_id,
367 f_tr_From(g_pars.cp.from_addr),
368 f_tr_To_response(g_pars.cp.to_addr),
369 f_tr_Via_response(via),
370 *,
371 tr_WwwAuthenticate({tr_Challenge_digestCln(?)}),
372 g_pars.cp.sip_seq_nr, "INVITE");
373 as_SIP_expect_resp(exp);
374
375 /* Digest Auth: RFC 2617 */
376 req.msgHeader.authorization := f_sip_digest_gen_Authorization(
377 g_rx_sip_resp.msgHeader.wwwAuthenticate,
378 g_pars.user, g_pars.password,
379 "INVITE",
380 f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri))
381 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
382 f_sip_Request_inc_seq_nr(req);
383 SIP.send(req);
384
385 /* Conditionally match and accept 100 Trying. */
386 exp := tr_SIP_Response_Trying(g_pars.cp.sip_call_id,
387 g_pars.cp.from_addr,
388 f_tr_To_response(g_pars.cp.to_addr),
389 f_tr_Via_response(via),
390 g_pars.cp.sip_seq_nr, "INVITE");
391 d_trying := activate(as_SIP_ignore_resp(exp));
392
393 /* Conditionally match and accept 180 Ringing */
394 exp := tr_SIP_Response_Ringing(g_pars.cp.sip_call_id,
395 g_pars.cp.from_addr,
396 f_tr_To_response(g_pars.cp.to_addr),
397 f_tr_Via_response(via),
398 g_pars.cp.sip_seq_nr, "INVITE");
399 d_ringing := activate(as_SIP_ignore_resp(exp));
400
401 /* Wait for OK answer */
402 exp := tr_SIP_Response(
403 g_pars.cp.sip_call_id,
404 g_pars.cp.from_addr,
405 f_tr_To_response(g_pars.cp.to_addr),
406 f_tr_Via_response(via),
407 *,
408 "INVITE", 200,
409 g_pars.cp.sip_seq_nr, "OK",
410 body := ?);
411 as_SIP_expect_resp(exp, fail_others := false);
412
413 deactivate(d_trying);
414 deactivate(d_ringing);
415
416 /* Update To with the tags received from peer: */
417 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(g_rx_sip_resp.msgHeader.toField.addressField,
418 g_rx_sip_resp.msgHeader.toField.toParams));
419
420 /* Transmit ACK */
421 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
422 req := ts_SIP_ACK(g_pars.cp.sip_call_id,
423 g_pars.cp.from_addr,
424 g_pars.cp.to_addr,
425 via,
426 g_pars.cp.sip_seq_nr,
427 omit);
428 SIP.send(req);
429 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
430}
431
432private function f_ConnHdlr_parse_initial_SIP_INVITE(PDU_SIP_Request rx_sip_req) runs on SIPConnHdlr
433{
434 f_SDP_decodeMessage(rx_sip_req.messageBody, g_pars.cp.peer_sdp);
435 log("Rx Initial MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
436
437 /* Obtain params: */
438 g_pars.cp.sip_call_id := rx_sip_req.msgHeader.callId.callid;
439 g_pars.cp.from_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.fromField.addressField,
440 rx_sip_req.msgHeader.fromField.fromParams));
441 g_pars.cp.to_addr := valueof(ts_SipAddr_from_Addr_Union(rx_sip_req.msgHeader.toField.addressField,
442 rx_sip_req.msgHeader.toField.toParams));
443 g_pars.cp.to_addr.params := f_sip_param_set(g_pars.cp.to_addr.params, "tag", f_sip_rand_tag());
444 g_pars.cp.sip_seq_nr := rx_sip_req.msgHeader.cSeq.seqNumber;
445}
446
447/* Peer is calling us, accept it: */
448altstep as_SIP_mt_call_accept(boolean exp_update_to_direct_rtp := true,
449 boolean fail_others := true) runs on SIPConnHdlr
450{
451 var template (present) PDU_SIP_Request exp_req :=
452 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
453 ?,
454 f_tr_From(g_pars.cp.calling),
455 g_pars.cp.called,
456 tr_Via_from(f_tr_HostPort(g_pars.remote_sip_host, g_pars.remote_sip_port)),
457 ?, ?);
458 var charstring sip_expect_str := log2str(exp_req);
459
460 [] SIP.receive(exp_req) -> value g_rx_sip_req {
461 var template (value) PDU_SIP_Response tx_resp;
462 var Via via;
463 var charstring tx_sdp;
464
465 /* Obtain params: */
466 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
467 via := g_rx_sip_req.msgHeader.via;
468
469
470 /* Tx 180 Ringing */
471 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
472 g_pars.cp.from_addr,
473 g_pars.cp.to_addr,
474 via,
475 g_pars.cp.sip_seq_nr);
476 SIP.send(tx_resp);
477
478 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
479 COORD.receive(COORD_CMD_PICKUP);
480 }
481
482 /* Tx 200 OK */
483 tx_sdp := f_gen_sdp();
484 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
485 g_pars.cp.from_addr,
486 g_pars.cp.to_addr,
487 "INVITE", 200,
488 g_pars.cp.sip_seq_nr,
489 "OK",
490 via,
491 body := tx_sdp);
492 SIP.send(tx_resp);
493
494 /* Wait for ACK */
495 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
496 g_pars.cp.sip_call_id,
497 g_pars.cp.from_addr,
498 g_pars.cp.to_addr,
499 f_tr_Via_response(via),
500 g_pars.cp.sip_seq_nr, *);
501 as_SIP_expect_req(exp_req);
502
503 if (exp_update_to_direct_rtp) {
504 /* Asterisk will now update the session to connect us to MO directly: */
505 /* Via is not kept since anyway "branch" will change upon following INVITE. */
506 as_SIP_exp_call_update(g_pars.cp.sip_seq_nr + 1);
507 }
508 }
509 [fail_others] as_SIP_fail_resp(sip_expect_str);
510 [fail_others] as_SIP_fail_req(sip_expect_str);
511
512}
513
514/* Peer is calling us, but cancells it during ringing: */
515altstep as_SIP_mt_call_cancelled(boolean fail_others := true) runs on SIPConnHdlr
516{
517 var template (present) PDU_SIP_Request exp_req :=
518 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
519 ?,
520 f_tr_From(g_pars.cp.calling),
521 g_pars.cp.called,
522 tr_Via_from(f_tr_HostPort(g_pars.remote_sip_host, g_pars.remote_sip_port)),
523 ?, ?);
524 var charstring sip_expect_str := log2str(exp_req);
525
526 [] SIP.receive(exp_req) -> value g_rx_sip_req {
527 var template (value) PDU_SIP_Response tx_resp;
528 var Via via;
529 var template (present) SipAddr exp_to_addr;
530 var charstring tx_sdp;
531
532 /* Obtain params: */
533 f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
534 via := g_rx_sip_req.msgHeader.via;
535
536
537 /* Tx 180 Ringing */
538 tx_resp := ts_SIP_Response_Ringing(g_pars.cp.sip_call_id,
539 g_pars.cp.from_addr,
540 g_pars.cp.to_addr,
541 via,
542 g_pars.cp.sip_seq_nr);
543 SIP.send(tx_resp);
544
545 if (g_pars.cp.mt.wait_coord_cmd_pickup) {
546 COORD.receive(COORD_CMD_PICKUP);
547 }
548
549 /* Wait for CANCEL */
550 /* Cancel may come even before we send Ringing, hence To's "tag"
551 * may not be known by peer, so g_pars.to_addr can't be used here: */
552 exp_to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
553 g_rx_sip_req.msgHeader.toField.toParams);
554 exp_req := tr_SIP_CANCEL(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
555 g_pars.cp.sip_call_id,
556 g_pars.cp.from_addr,
557 exp_to_addr,
558 f_tr_Via_response(via),
559 g_pars.cp.sip_seq_nr, *);
560 as_SIP_expect_req(exp_req);
561
562 /* Tx 200 OK */
563 tx_sdp := f_gen_sdp();
564 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
565 g_pars.cp.from_addr,
566 g_pars.cp.to_addr,
567 "CANCEL", 200,
568 g_pars.cp.sip_seq_nr,
569 "OK",
570 via,
571 body := omit);
572 SIP.send(tx_resp);
573 }
574 [fail_others] as_SIP_fail_resp(sip_expect_str);
575 [fail_others] as_SIP_fail_req(sip_expect_str);
576
577}
578
579/* New INVITE arrives after MT call is established. Accept it: */
580altstep as_SIP_exp_call_update(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on SIPConnHdlr
581{
582 var template (present) PDU_SIP_Request exp_req :=
583 tr_SIP_INVITE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
584 g_pars.cp.sip_call_id,
585 g_pars.cp.from_addr,
586 g_pars.cp.to_addr,
587 tr_Via_from(f_tr_HostPort(g_pars.remote_sip_host, g_pars.remote_sip_port)),
588 exp_seq_nr,
589 ?);
590 var charstring sip_expect_str := log2str(exp_req);
591
592 [] SIP.receive(exp_req) -> value g_rx_sip_req {
593 var template (value) PDU_SIP_Response tx_resp;
594 var charstring tx_sdp;
595 var Via via;
596
597 f_SDP_decodeMessage(g_rx_sip_req.messageBody, g_pars.cp.peer_sdp);
598 log("Rx Update MT INVITE decoded SDP: ", g_pars.cp.peer_sdp);
599
600 /* Update parameters: */
601 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
602 /* "branch" has changed: */
603 via := g_rx_sip_req.msgHeader.via;
604
605 /* Tx 200 OK */
606 tx_sdp := f_gen_sdp();
607 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
608 g_pars.cp.from_addr,
609 g_pars.cp.to_addr,
610 "INVITE", 200,
611 g_pars.cp.sip_seq_nr,
612 "OK",
613 via,
614 body := tx_sdp);
615 SIP.send(tx_resp);
616
617 /* Wait for ACK */
618 exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
619 g_pars.cp.sip_call_id,
620 g_pars.cp.from_addr,
621 g_pars.cp.to_addr,
622 f_tr_Via_response(via),
623 g_pars.cp.sip_seq_nr, *);
624 as_SIP_expect_req(exp_req);
625 }
626 [fail_others] as_SIP_fail_resp(sip_expect_str);
627 [fail_others] as_SIP_fail_req(sip_expect_str);
628}
629
630/* Tx BYE: */
631function f_SIP_do_call_hangup() runs on SIPConnHdlr
632{
633 var template (value) PDU_SIP_Request req;
634 var template (present) PDU_SIP_Response exp_resp;
635 var Via via;
636 var charstring branch_value;
637
638 branch_value := f_sip_gen_branch(f_sip_SipAddr_to_str(g_pars.cp.from_addr),
639 f_sip_SipAddr_to_str(valueof(g_pars.cp.to_addr)),
640 g_pars.cp.sip_call_id,
641 g_pars.cp.sip_seq_nr);
642
643 via := g_pars.local_via;
644 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "branch", branch_value);
645
646 /* Transmit ACK */
647 req := ts_SIP_BYE(g_pars.cp.sip_call_id,
648 g_pars.cp.from_addr,
649 g_pars.cp.to_addr,
650 via,
651 g_pars.cp.sip_seq_nr,
652 omit);
653 SIP.send(req);
654
655 /* Wait for OK answer */
656 exp_resp := tr_SIP_Response(
657 g_pars.cp.sip_call_id,
658 g_pars.cp.from_addr,
659 f_tr_To_response(g_pars.cp.to_addr),
660 f_tr_Via_response(via),
661 *,
662 "BYE", 200,
663 g_pars.cp.sip_seq_nr, "OK");
664 as_SIP_expect_resp(exp_resp);
665
666 g_pars.cp.sip_seq_nr := g_pars.cp.sip_seq_nr + 1;
667}
668
669/* Call is terminated by peer: */
670altstep as_SIP_exp_call_hangup(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on SIPConnHdlr
671{
672 var template (present) PDU_SIP_Request exp_req :=
673 tr_SIP_BYE(f_tr_SipUrl_opt_defport(g_pars.local_sip_url_ext),
674 g_pars.cp.sip_call_id,
675 g_pars.cp.from_addr,
676 g_pars.cp.to_addr,
677 tr_Via_from(f_tr_HostPort(g_pars.remote_sip_host, g_pars.remote_sip_port)),
678 exp_seq_nr);
679 var charstring sip_expect_str := log2str(exp_req);
680
681 [] SIP.receive(exp_req) -> value g_rx_sip_req {
682 var template (value) PDU_SIP_Response tx_resp;
683 var charstring tx_sdp;
684 var Via via;
685
686 /* Update parameters: */
687 g_pars.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
688 /* "branch" has changed: */
689 via := g_rx_sip_req.msgHeader.via;
690
691 /* Tx 200 OK */
692 tx_sdp := f_gen_sdp();
693 tx_resp := ts_SIP_Response(g_pars.cp.sip_call_id,
694 g_pars.cp.from_addr,
695 g_pars.cp.to_addr,
696 "BYE", 200,
697 g_pars.cp.sip_seq_nr,
698 "OK",
699 via,
700 body := tx_sdp);
701 SIP.send(tx_resp);
702 }
703 [fail_others] as_SIP_fail_resp(sip_expect_str);
704 [fail_others] as_SIP_fail_req(sip_expect_str);
705}
706
707}