blob: 9fbe9731356b9e6b8f2202efd3fa41b9d44bc5e4 [file] [log] [blame]
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +02001/* Asterisk's AMI interface functions in TTCN-3
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 */
11
12/*
13 * https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/AMI-v2-Specification/
14 */
15module AMI_Functions {
16
17import from Misc_Helpers all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020018import from Osmocom_Types all;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +020019import from IPL4asp_Types all;
20import from IPL4asp_PortType all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020021import from Socket_API_Definitions all;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +020022import from TCCConversion_Functions all;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020023
24modulepar {
25 float mp_ami_prompt_timeout := 10.0;
26}
27
28const charstring AMI_FIELD_ACTION := "Action";
Pau Espin Pedrol941ca3c2024-05-09 16:46:58 +020029const charstring AMI_FIELD_ACTION_ID := "ActionID";
Pau Espin Pedrole98f4412024-05-17 19:33:46 +020030const charstring AMI_FIELD_EVENT := "Event";
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020031const charstring AMI_FIELD_USERNAME := "Username";
32const charstring AMI_FIELD_SECRET := "Secret";
33const charstring AMI_FIELD_RESPONSE := "Response";
34
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020035/* Extensions: */
36const charstring AMI_FIELD_REGISTRATION := "Registration";
37
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020038type record AMI_Field {
39 charstring key,
40 charstring val
Pau Espin Pedrolde7a4852024-04-19 16:20:45 +020041} with {
42 encode "TEXT"
43 variant "SEPARATOR(': ', ':\s+')"
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020044};
Pau Espin Pedrolde7a4852024-04-19 16:20:45 +020045
46type set of AMI_Field AMI_Msg with {
47 encode "TEXT"
48 variant "SEPARATOR('\r\n', '(\r\n)|[\n]')"
49 variant "END('\r\n', '(\r\n)|[\n]')"
50};
51
52external function enc_AMI_Msg(in AMI_Msg msg) return charstring
53 with { extension "prototype(convert) encode(TEXT)" }
54external function dec_AMI_Msg(in charstring stream) return AMI_Msg
55 with { extension "prototype(convert) decode(TEXT)" }
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020056
57template (value) AMI_Field
58ts_AMI_Field(template (value) charstring key,
59 template (value) charstring val) := {
60 key := key,
61 val := val
62};
63
64template (present) AMI_Field
65tr_AMI_Field(template (present) charstring key := ?,
66 template (present) charstring val := ?) := {
67 key := key,
68 val := val
69};
70
71/*
72 * Field Templates:
73 */
74
75template (value) AMI_Field
76ts_AMI_Field_Action(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_ACTION, val);
77template (value) AMI_Field
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020078ts_AMI_Field_ActionId(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_ACTION_ID, val);
79template (value) AMI_Field
Pau Espin Pedrole98f4412024-05-17 19:33:46 +020080ts_AMI_Field_Event(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_EVENT, val);
81template (value) AMI_Field
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020082ts_AMI_Field_Username(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_USERNAME, val);
83template (value) AMI_Field
84ts_AMI_Field_Secret(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_SECRET, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020085/* Extensions: */
86template (value) AMI_Field
87ts_AMI_Field_Registration(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_REGISTRATION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020088
89template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020090tr_AMI_Field_Action(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_ACTION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020091template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020092tr_AMI_Field_ActionId(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_ACTION_ID, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +020093template (present) AMI_Field
Pau Espin Pedrole98f4412024-05-17 19:33:46 +020094tr_AMI_Field_Event(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_EVENT, val);
95template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020096tr_AMI_Field_Username(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_USERNAME, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020097template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +020098tr_AMI_Field_Secret(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_SECRET, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +020099template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +0200100tr_AMI_Field_Response(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_RESPONSE, val);
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200101/* Extensions: */
102template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +0200103tr_AMI_Field_Registration(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_REGISTRATION, val);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200104
105
106template (present) AMI_Field
Pau Espin Pedrol21c084f2024-05-09 16:42:16 +0200107tr_AMI_Field_ResponseSuccess := tr_AMI_Field(pattern @nocase AMI_FIELD_RESPONSE, "Success");
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200108
109
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200110/***********************
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200111 * Message Templates:
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200112 ***********************/
113
114/*
115 * ACTIONS
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200116 */
117
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200118/* Action: Login
119 * Username: <value>
120 * Secret: <value>
121 */
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200122template (value) AMI_Msg
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200123ts_AMI_Action_Login(charstring username,
124 charstring secret,
125 template (value) charstring action_id := "0001") := {
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200126 ts_AMI_Field_Action("Login"),
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200127 ts_AMI_Field_ActionId(action_id),
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200128 ts_AMI_Field_Username(username),
129 ts_AMI_Field_Secret(secret)
130};
131
132template (present) AMI_Msg
133tr_AMI_Action_Login(template(present) charstring username := ?,
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200134 template(present) charstring secret := ?,
135 template (present) charstring action_id := ?) := superset(
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200136 tr_AMI_Field_Action("Login"),
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200137 tr_AMI_Field_ActionId(action_id),
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200138 tr_AMI_Field_Username(username),
139 tr_AMI_Field_Secret(secret)
140);
141
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200142/* Action: PJSIPRegister
143 * ActionID: <value>
144 * Registration: volte_ims
145 */
146template (value) AMI_Msg
147ts_AMI_Action_PJSIPRegister(template (value) charstring registration := "volte_ims",
148 template (value) charstring action_id := "0001") := {
149 ts_AMI_Field_Action("PJSIPRegister"),
150 ts_AMI_Field_ActionId(action_id),
151 ts_AMI_Field_Registration(registration)
152};
153template (present) AMI_Msg
154tr_AMI_Action_PJSIPRegister(template (present) charstring registration := ?,
155 template (present) charstring action_id := ?) := {
156 tr_AMI_Field_Action("PJSIPRegister"),
157 tr_AMI_Field_ActionId(action_id),
158 tr_AMI_Field_Registration(registration)
159};
160
161/*
162 * RESPONSES
163 */
164
165/* Response: Success
166 */
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200167template (present) AMI_Msg
168tr_AMI_Response_Success := superset(
169 tr_AMI_Field_ResponseSuccess
170);
171
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200172/* Response: Success
173 * ActionId: <value>
174 */
175template (present) AMI_Msg
176tr_AMI_Response_Success_ActionId(template (present) charstring action_id := ?) := superset(
177 tr_AMI_Field_ResponseSuccess,
178 tr_AMI_Field_ActionId(action_id)
179);
180
Pau Espin Pedrole98f4412024-05-17 19:33:46 +0200181/*
182 * EVENTS
183 */
184template (present) AMI_Msg
185tr_AMI_Event(template (present) charstring ev_name := ?) := superset(
186 tr_AMI_Field_Event(ev_name)
187);
188
189/* Event: FullyBooted
190 * Privilege: system,all
191 * Status: Fully Booted
192 * Uptime: 4
193 * LastReload: 4 *
194 */
195template (present) AMI_Msg
196tr_AMI_Event_FullyBooted := tr_AMI_Event("FullyBooted");
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200197
198/***********************
199 * Adapter:
200 ***********************/
201
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200202type record AMI_Adapter_Parameters {
203 charstring remote_host,
204 IPL4asp_Types.PortNumber remote_port,
205 charstring local_host,
206 IPL4asp_Types.PortNumber local_port,
207 charstring welcome_str
208}
209
210const AMI_Adapter_Parameters c_default_AMI_Adapter_pars := {
211 remote_host := "127.0.0.1",
212 remote_port := 5038,
213 local_host := "0.0.0.0",
214 local_port := 0,
215 welcome_str := "Asterisk Call Manager/9.0.0\r\n"
216};
217
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200218type port AMI_Msg_PT message {
219 inout AMI_Msg;
220} with { extension "internal" };
221
222type component AMI_Adapter_CT {
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200223 port IPL4asp_PT IPL4;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200224 port AMI_Msg_PT CLIENT;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200225 var AMI_Adapter_Parameters g_pars;
226
227 /* Connection identifier of the client itself */
228 var IPL4asp_Types.ConnectionId g_self_conn_id := -1;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200229}
230
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200231/* Function to use to connect as client to a remote IPA Server */
232private function f_AMI_Adapter_connect() runs on AMI_Adapter_CT {
233 var IPL4asp_Types.Result res;
234 map(self:IPL4, system:IPL4);
235 res := IPL4asp_PortType.f_IPL4_connect(IPL4, g_pars.remote_host, g_pars.remote_port,
236 g_pars.local_host, g_pars.local_port, 0, { tcp:={} });
237 if (not ispresent(res.connId)) {
238 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
239 log2str("Could not connect AMI socket from ", g_pars.local_host, " port ",
240 g_pars.local_port, " to ", g_pars.remote_host, " port ", g_pars.remote_port,
241 "; check your configuration"));
242 }
243 g_self_conn_id := res.connId;
244 log("AMI connected, ConnId=", g_self_conn_id)
245}
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200246
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200247private function f_ASP_RecvFrom_msg_to_charstring(ASP_RecvFrom rx_rf) return charstring {
248 return oct2char(rx_rf.msg);
249}
250
251/* Function to use to connect as client to a remote IPA Server */
252private function f_AMI_Adapter_wait_rx_welcome_str() runs on AMI_Adapter_CT {
253 var ASP_RecvFrom rx_rf;
254 var charstring rx_str;
255 timer Twelcome := 3.0;
256
257 Twelcome.start;
258 alt {
259 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
260 rx_str := f_ASP_RecvFrom_msg_to_charstring(rx_rf);
261 if (g_pars.welcome_str != rx_str) {
262 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
263 log2str("AMI Welcome message mismatch: '", rx_str,
264 "' vs exp '", g_pars.welcome_str, "'"));
265 }
266 }
267 [] Twelcome.timeout {
268 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
269 log2str("AMI Welcome timeout"));
270 }
271 }
272 Twelcome.stop;
273 log("AMI Welcome message received: '", rx_str, "'");
274}
275
276private function dec_AMI_Msg_ext(charstring txt) return AMI_Msg {
277 log("AMI dec: '", txt, "'");
278 /* TEXT Enc/dec is not happy with empty values, workaround it: */
279 var charstring patched_txt := f_str_replace(txt, "Challenge: \r\n", "");
280 patched_txt := f_str_replace(patched_txt, "AccountCode: \r\n", "");
281 patched_txt := f_str_replace(patched_txt, "Value: \r\n", "");
282 patched_txt := f_str_replace(patched_txt, "DestExten: \r\n", "");
283 patched_txt := f_str_replace(patched_txt, "Exten: \r\n", "");
284 patched_txt := f_str_replace(patched_txt, "Extension: \r\n", "");
Pau Espin Pedrolbf0e14d2024-05-16 18:34:13 +0200285 patched_txt := f_str_replace(patched_txt, "Hint: \r\n", "");
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200286
287 /* "AppData" field sometimes has a value containing separator ": ", which makes
288 * TEXT dec not happy. Workaround it for now by removing the whole field line:
289 * "AppData: 5,0502: Call pjsip endpoint from 0501\r\n"
290 */
291 var integer pos := f_strstr(patched_txt, "AppData: ", 0);
292 if (pos >= 0) {
293 var integer pos_end := f_strstr(patched_txt, "\r\n", pos) + lengthof("\r\n");
294 var charstring to_remove := substr(patched_txt, pos, pos_end - pos);
295 patched_txt := f_str_replace(patched_txt, to_remove, "");
296 }
297
298 log("AMI patched dec: '", patched_txt, "'");
299 return dec_AMI_Msg(patched_txt);
300}
301
302function f_AMI_Adapter_main(AMI_Adapter_Parameters pars := c_default_AMI_Adapter_pars)
303 runs on AMI_Adapter_CT {
304 var AMI_Msg msg;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200305 var charstring rx, buf := "";
306 var integer fd;
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200307 var ASP_RecvFrom rx_rf;
308 var ASP_Event rx_ev;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200309
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200310 g_pars := pars;
311
312 f_AMI_Adapter_connect();
313
314 f_AMI_Adapter_wait_rx_welcome_str();
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200315
316 while (true) {
317
318 alt {
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200319 [] IPL4.receive(ASP_RecvFrom:?) -> value rx_rf {
320 var charstring rx_str := f_ASP_RecvFrom_msg_to_charstring(rx_rf);
321 log("AMI rx: '", rx_str, "'");
322 buf := buf & rx_str;
323 log("AMI buf: '", buf, "'");
324
325 /* If several messages come together */
326 var boolean last_is_complete := f_str_endswith(buf, "\r\n\r\n");
327 var Misc_Helpers.ro_charstring msgs := f_str_split(buf, "\r\n\r\n");
328 log("AMI split: ", msgs);
329 if (lengthof(msgs) > 0) {
330 for (var integer i := 0; i < lengthof(msgs) - 1; i := i + 1) {
331 var charstring txt := msgs[i] & "\r\n";
332 msg := dec_AMI_Msg_ext(txt);
333 CLIENT.send(msg);
334 }
335 if (last_is_complete) {
336 var charstring txt := msgs[lengthof(msgs) - 1] & "\r\n";
337 msg := dec_AMI_Msg_ext(txt);
338 CLIENT.send(msg);
339 buf := "";
340 } else {
341 buf := msgs[lengthof(msgs) - 1];
342 }
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200343 }
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200344 log("AMI remain buf: '", buf, "'");
345 }
346 [] IPL4.receive(ASP_ConnId_ReadyToRelease:?) {
347 }
348
349 [] IPL4.receive(ASP_Event:?) -> value rx_ev {
350 log("Rx AMI ASP_Event: ", rx_ev);
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200351 }
352 [] CLIENT.receive(AMI_Msg:?) -> value msg {
353 /* TODO: in the future, queue Action if there's already one Action in transit, to fullfill AMI requirements. */
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200354 var charstring tx_txt := enc_AMI_Msg(msg) & "\r\n";
355
356 var ASP_SendTo tx := {
357 connId := g_self_conn_id,
358 remName := g_pars.remote_host,
359 remPort := g_pars.remote_port,
360 proto := { tcp := {} },
361 msg := char2oct(tx_txt)
362 };
363 IPL4.send(tx);
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200364 }
365 }
366 }
367}
368
369
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200370/*
371 * Functions:
372 */
373
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200374/* Generate a random "ActionId" value: */
375function f_gen_action_id() return charstring {
376 return hex2str(f_rnd_hexstring(16));
377}
378
379function f_ami_msg_find(AMI_Msg msg,
380 template (present) charstring key := ?)
381return template (omit) AMI_Field {
382 var integer i;
383
384 for (i := 0; i < lengthof(msg); i := i + 1) {
385 if (not ispresent(msg[i])) {
386 continue;
387 }
388 if (match(msg[i].key, key)) {
389 return msg[i];
390 }
391 }
392 return omit;
393}
394
395function f_ami_msg_find_or_fail(AMI_Msg msg,
396 template (present) charstring key := ?)
397return AMI_Field {
398 var template (omit) AMI_Field field;
399 field := f_ami_msg_find(msg, key);
400 if (istemplatekind(field, "omit")) {
401 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
402 log2str("Key ", key, " not found in ", msg));
403 }
404 return valueof(field);
405}
406
407function f_ami_msg_get_value(AMI_Msg msg,
408 template (present) charstring key := ?)
409return template (omit) charstring {
410 var template (omit) AMI_Field field;
411 field := f_ami_msg_find(msg, key);
412 if (istemplatekind(field, "omit")) {
413 return omit;
414 }
415 return field.val;
416}
417
418function f_ami_msg_get_value_or_fail(AMI_Msg msg,
419 template (present) charstring key := ?)
420return template charstring {
421 var AMI_Field field;
422 field := f_ami_msg_find_or_fail(msg, key);
423 return field.val;
424}
425
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200426function f_ami_transceive_ret(AMI_Msg_PT pt, template (value) AMI_Msg tx_msg, float rx_timeout := 10.0) return AMI_Msg {
427 var AMI_Msg rx_msg;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200428 timer T;
429
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200430 T.start(rx_timeout);
431 pt.send(tx_msg);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200432 alt {
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200433 [] pt.receive(AMI_Msg:?) -> value rx_msg;
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200434 [] T.timeout {
435 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200436 log2str("AMI Response timeout: ", tx_msg));
437 }
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200438 }
439 T.stop;
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200440 return rx_msg;
441
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200442}
443
Pau Espin Pedrole98f4412024-05-17 19:33:46 +0200444altstep as_ami_rx_ignore(AMI_Msg_PT pt)
445{
446 var AMI_Msg msg;
447 [] pt.receive(AMI_Msg:?) -> value msg {
448 log("Ignoring AMI message := ", msg);
449 repeat;
450 }
451}
452
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200453private altstep as_ami_rx_fail(AMI_Msg_PT pt, template AMI_Msg exp_msg := *)
454{
455 var AMI_Msg msg;
456 [] pt.receive(AMI_Msg:?) -> value msg {
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200457 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200458 log2str("Received unexpected AMI message := ", msg, "\nvs exp := ", exp_msg));
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200459 }
460}
461
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200462altstep as_ami_expect_msg(AMI_Msg_PT pt, template (present) AMI_Msg msg_expect, boolean fail_others := true)
463{
464 [] pt.receive(msg_expect);
465 [fail_others] as_ami_rx_fail(pt, msg_expect);
466}
467
468function f_ami_transceive_match(AMI_Msg_PT pt,
469 template (value) AMI_Msg tx_msg,
470 template (present) AMI_Msg exp_ret := ?,
471 boolean fail_others := true,
472 float rx_timeout := 10.0) return AMI_Msg {
473 var AMI_Msg rx_msg;
474 timer T;
475
476 T.start(rx_timeout);
477 pt.send(tx_msg);
478 alt {
479 [] pt.receive(exp_ret) -> value rx_msg;
480 [not fail_others] pt.receive(AMI_Msg:?) -> value rx_msg {
481 log("AMI: Ignoring Rx msg ", rx_msg);
482 repeat;
483 }
484 [fail_others] as_ami_rx_fail(pt, exp_ret);
485 [] T.timeout {
486 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
487 log2str("AMI Response timeout: ", tx_msg));
488 }
489 }
490 T.stop;
491 return rx_msg;
492}
493
494function f_ami_transceive_match_response_success(AMI_Msg_PT pt,
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200495 template (value) AMI_Msg tx_msg) {
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200496 var template (present) AMI_Msg exp_resp;
497 var template (omit) charstring action_id := f_ami_msg_get_value(valueof(tx_msg), AMI_FIELD_ACTION_ID);
498 if (isvalue(action_id)) {
499 exp_resp := tr_AMI_Response_Success_ActionId(action_id);
500 } else {
501 exp_resp := tr_AMI_Response_Success;
502 }
503 f_ami_transceive_match(pt, tx_msg, exp_resp);
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200504}
505
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200506function f_ami_action_login(AMI_Msg_PT pt, charstring username, charstring secret) {
Pau Espin Pedrol77976a62024-05-08 21:17:38 +0200507 var charstring reg_action_id := f_gen_action_id();
508 f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret, reg_action_id));
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200509}
510
Pau Espin Pedrolbcb4e822024-04-26 20:16:47 +0200511function f_ami_action_PJSIPRegister(AMI_Msg_PT pt, charstring register) {
Pau Espin Pedrol4362dbd2024-04-26 19:31:27 +0200512 var charstring reg_action_id := f_gen_action_id();
513 f_ami_transceive_match_response_success(pt, ts_AMI_Action_PJSIPRegister(register, reg_action_id));
514}
515
Pau Espin Pedrol01f1df82024-05-08 16:55:55 +0200516private function f_ami_selftest_decode(charstring txt) {
517 log("Text to decode: '", txt, "'");
518 var AMI_Msg msg := dec_AMI_Msg(txt);
519 log("AMI_Msg decoded: ", msg);
520}
521
522function f_ami_selftest() {
523 f_ami_selftest_decode("AppData: 5,0502: Call pjsip endpoint from 0501\r\n");
524}
525
Pau Espin Pedrol54b614a2024-04-17 18:58:36 +0200526}