173 lines
5.3 KiB
Plaintext
173 lines
5.3 KiB
Plaintext
/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
|
* Author: Stefan Sperling <ssperling@sysmocom.de>
|
|
* All Rights Reserved
|
|
*
|
|
* Released under the terms of GNU General Public License, Version 2 or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/*
|
|
* This module provides functions which implement IPA protocol tests.
|
|
* There are no test cases defined here. Instead, there are test functions which
|
|
* can be called by test cases in our test suites. Each such function will create
|
|
* an IPA_CT component and execute a test on this component, and expects destination
|
|
* IP address, TCP port, and connection mode parameters. Depending on the connection
|
|
* mode, a test function will either connect to an IPA server on the specified
|
|
* address and port, or listen for an IPA client on the specified address and port.
|
|
* This allows IPA tests to be run against any IPA speakers used by various test suites.
|
|
*/
|
|
|
|
module IPA_Testing {
|
|
|
|
import from IPL4asp_Types all;
|
|
import from IPL4asp_PortType all;
|
|
import from IPA_Types all;
|
|
import from Osmocom_Types all;
|
|
|
|
type enumerated IPA_ConnectionMode {
|
|
CONNECT_TO_SERVER,
|
|
LISTEN_FOR_CLIENT
|
|
};
|
|
|
|
/* Encoded IPA messages (network byte order) */
|
|
const octetstring ipa_msg_ping := '0001FE00'O;
|
|
const octetstring ipa_msg_pong := '0001FE01'O;
|
|
|
|
/* A component which represents the system on which the IPA speaker is running. */
|
|
type component system_CT {
|
|
port IPL4asp_PT IPL4;
|
|
}
|
|
|
|
/* Main component provided by this module. */
|
|
type component IPA_CT {
|
|
port IPL4asp_PT IPL4;
|
|
timer g_Tguard;
|
|
}
|
|
|
|
/* This guard timer prevents us from waiting too long if the IPA TCP connection hangs. */
|
|
private altstep as_Tguard() runs on IPA_CT {
|
|
[] g_Tguard.timeout {
|
|
setverdict(fail, "Tguard timeout");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* Send an encoded IPA message across an IPA TCP connection. */
|
|
private function f_send_ipa_data(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId,
|
|
octetstring data) runs on IPA_CT {
|
|
var IPL4asp_Types.Result res;
|
|
var ASP_SendTo asp := {
|
|
connId := connId,
|
|
remName := ipa_ip,
|
|
remPort := ipa_tcp_port,
|
|
proto := {tcp := {}},
|
|
msg := data
|
|
};
|
|
IPL4.send(asp);
|
|
}
|
|
|
|
/* Match an incoming IPA message. */
|
|
private template ASP_RecvFrom t_recvfrom(template octetstring msg) := {
|
|
connId := ?,
|
|
remName := ?,
|
|
remPort := ?,
|
|
locName := ?,
|
|
locPort := ?,
|
|
proto := {tcp := {}},
|
|
userData := ?,
|
|
msg := msg
|
|
}
|
|
|
|
/* Perform set up steps for a test function. */
|
|
private function f_init(charstring ipa_ip, integer ipa_tcp_port,
|
|
IPA_ConnectionMode conmode) runs on IPA_CT return ConnectionId {
|
|
var IPL4asp_Types.Result res;
|
|
var ConnectionId connId;
|
|
|
|
map(self:IPL4, system:IPL4);
|
|
if (conmode == CONNECT_TO_SERVER) {
|
|
/* Create an IPA connection over TCP. */
|
|
res := IPL4asp_PortType.f_IPL4_connect(IPL4, ipa_ip, ipa_tcp_port, "", -1, 0, {tcp := {}});
|
|
if (not ispresent(res.connId)) {
|
|
setverdict(fail, "Could not connect IPA socket to ", ipa_ip, " port ",
|
|
ipa_tcp_port, "; check your configuration");
|
|
mtc.stop;
|
|
}
|
|
} else {
|
|
/* Listen for an incoming IPA connection on TCP. */
|
|
res := IPL4asp_PortType.f_IPL4_listen(IPL4, ipa_ip, ipa_tcp_port, {tcp := {}});
|
|
if (not ispresent(res.connId)) {
|
|
setverdict(fail, "Could not listen on address ", ipa_ip, " port ",
|
|
ipa_tcp_port, "; check your configuration");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Activate guard timer. When changing the timeout value, keep in mind
|
|
* that test functions below may wait for some amount of time, which
|
|
* this guard timer should always exceed to avoid spurious failures.
|
|
*/
|
|
g_Tguard.start(60.0);
|
|
activate(as_Tguard());
|
|
|
|
return res.connId;
|
|
}
|
|
|
|
/*
|
|
* Individual test case implementations.
|
|
*/
|
|
|
|
private function f_send_chopped_ipa_msg(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId,
|
|
octetstring msg) runs on IPA_CT {
|
|
const float delay := 6.0;
|
|
for (var integer i := 0; i < lengthof(msg); i := i + 1) {
|
|
log("sending byte ", msg[i]);
|
|
f_send_ipa_data(ipa_ip, ipa_tcp_port, connId, msg[i]);
|
|
f_sleep(delay);
|
|
}
|
|
}
|
|
|
|
/* Send a ping message one byte at a time, waiting for TCP buffer to flush between each byte. */
|
|
private function f_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port,
|
|
IPA_ConnectionMode conmode) runs on IPA_CT system system_CT {
|
|
var ConnectionId connId;
|
|
var ASP_RecvFrom asp_rx;
|
|
|
|
connId := f_init(ipa_ip, ipa_tcp_port, conmode);
|
|
|
|
if (conmode == CONNECT_TO_SERVER) {
|
|
f_send_chopped_ipa_msg(ipa_ip, ipa_tcp_port, connId, ipa_msg_ping);
|
|
} else {
|
|
var PortEvent port_evt;
|
|
IPL4.receive(PortEvent:{connOpened := ?}) -> value port_evt {
|
|
var ConnectionOpenedEvent conn := port_evt.connOpened;
|
|
f_send_chopped_ipa_msg(conn.remName, conn.remPort, conn.connId, ipa_msg_ping);
|
|
}
|
|
}
|
|
|
|
/* Expect a pong response. */
|
|
alt {
|
|
[] IPL4.receive(t_recvfrom(ipa_msg_pong)) -> value asp_rx {
|
|
log("received pong from ", asp_rx.remName, " port ", asp_rx.remPort, ": ", asp_rx.msg);
|
|
setverdict(pass);
|
|
}
|
|
[] IPL4.receive {
|
|
repeat;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Public functions.
|
|
* Test suites may call these functions to create an IPA_CT component and run a test to completion.
|
|
*/
|
|
|
|
function f_run_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port, IPA_ConnectionMode conmode) {
|
|
var IPA_Testing.IPA_CT vc_IPA_Testing := IPA_Testing.IPA_CT.create;
|
|
vc_IPA_Testing.start(IPA_Testing.f_TC_chopped_ipa_ping(ipa_ip, ipa_tcp_port, conmode));
|
|
vc_IPA_Testing.done;
|
|
}
|
|
|
|
}
|