Initial test suite for osmo-pcap-client
Change-Id: If4a1072e75cb64f785d660e4c828c0f521d84b16
diff --git a/pcap-client/OPCAP_CLIENT_Tests.cfg b/pcap-client/OPCAP_CLIENT_Tests.cfg
new file mode 100644
index 0000000..3476c2f
--- /dev/null
+++ b/pcap-client/OPCAP_CLIENT_Tests.cfg
@@ -0,0 +1,18 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./OPCAP_CLIENT_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+OPCAP_CLIENT_Tests.control
diff --git a/pcap-client/OPCAP_CLIENT_Tests.default b/pcap-client/OPCAP_CLIENT_Tests.default
new file mode 100644
index 0000000..2b1677b
--- /dev/null
+++ b/pcap-client/OPCAP_CLIENT_Tests.default
@@ -0,0 +1,19 @@
+[LOGGING]
+mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
+
+[TESTPORT_PARAMETERS]
+*.VTY.CTRL_MODE := "client"
+*.VTY.CTRL_HOSTNAME := "127.0.0.1"
+*.VTY.CTRL_PORTNUM := "4237"
+*.VTY.CTRL_LOGIN_SKIPPED := "yes"
+*.VTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes"
+*.VTY.CTRL_READMODE := "buffered"
+*.VTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
+*.VTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
+*.VTY.PROMPT1 := "OsmoPCAPClient> "
+*.TCP.noDelay := "yes" // turn off nagle
+
+[MODULE_PARAMETERS]
+Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoPCAPClient"
+
+[EXECUTE]
diff --git a/pcap-client/OPCAP_CLIENT_Tests.ttcn b/pcap-client/OPCAP_CLIENT_Tests.ttcn
new file mode 100644
index 0000000..5f59caf
--- /dev/null
+++ b/pcap-client/OPCAP_CLIENT_Tests.ttcn
@@ -0,0 +1,212 @@
+module OPCAP_CLIENT_Tests {
+
+import from OPCAP_Adapter all;
+import from OPCAP_Types all;
+import from OPCAP_Templates all;
+
+import from IPL4asp_Types all;
+import from IPL4asp_PortType all;
+import from Osmocom_Types all;
+import from Osmocom_VTY_Functions all;
+import from TELNETasp_PortType all;
+import from Socket_API_Definitions all;
+
+type record IpPort {
+ charstring ip,
+ integer udp_port
+};
+
+modulepar {
+ /* local IP address listening for OPCAP connections */
+ charstring mp_local_opcap_ip := "127.0.0.1";
+ /* local TCP base port for inbound OPCAP connections */
+ integer mp_local_opcap_port := 5000;
+
+ /* IP + port for simulating user traffic */
+ IpPort mp_traffic_a := { "127.0.0.23", 44423 };
+ IpPort mp_traffic_b := { "127.0.0.42", 44442 };
+};
+
+type component test_CT extends OPCAP_Adapter_CT {
+ timer g_Tguard := 30.0;
+
+ port TELNETasp_PT VTY;
+
+ /* port to generate IP traffic that may or may not be captured */
+ port IPL4asp_PT IP;
+ var integer g_traffic_conn_id[2];
+};
+
+private altstep as_Tguard() runs on test_CT {
+[] g_Tguard.timeout {
+ setverdict(fail, "global guard timeout");
+ mtc.stop;
+ }
+}
+
+/* initialize one of the OPCAP servers, wait for client to connect */
+private function f_init_one_srv(integer idx, template (present) uint32_t linktype) runs on test_CT {
+ /* start guard timer */
+ activate(as_Tguard());
+ g_Tguard.start;
+ log("Waiting for client-", idx, " connection...");
+ /* wait for connection */
+ f_bind(mp_local_opcap_ip, mp_local_opcap_port+idx, idx);
+ f_wait_client_connect(idx);
+ /* wait for file header */
+ f_opcap_exp(tr_OPCAP_FILE_HDR(linktype), idx);
+};
+
+
+/* global initialization */
+private function f_init() runs on test_CT {
+ map(self:VTY, system:VTY);
+ f_vty_set_prompts(VTY);
+ f_vty_transceive(VTY, "enable");
+
+ map(self:IP, system:IP);
+ var IPL4asp_Types.Result res
+
+ /* 0 -> 1 */
+ res := f_IPL4_connect(IP, mp_traffic_b.ip, mp_traffic_b.udp_port,
+ mp_traffic_a.ip, mp_traffic_a.udp_port, -1, { udp:={} });
+ g_traffic_conn_id[0] := res.connId;
+
+ /* 1 -> 0 */
+ res := f_IPL4_connect(IP, mp_traffic_a.ip, mp_traffic_a.udp_port,
+ mp_traffic_b.ip, mp_traffic_b.udp_port, -1, { udp:={} });
+ g_traffic_conn_id[1] := res.connId;
+}
+
+/* generate user traffic from A -> B */
+function f_trafic_pkt_ab(octetstring payload) runs on test_CT {
+ IP.send(ASP_Send:{g_traffic_conn_id[0], omit, payload})
+ IP.receive(ASP_RecvFrom:{g_traffic_conn_id[1], ?, ?, ?, ?, { udp:={} }, ?, payload});
+}
+
+/* generate user traffic from B -> A */
+function f_trafic_pkt_ba(octetstring payload) runs on test_CT {
+ IP.send(ASP_Send:{g_traffic_conn_id[1], omit, payload})
+ IP.receive(ASP_RecvFrom:{g_traffic_conn_id[0], ?, ?, ?, ?, { udp:={} }, ?, payload});
+}
+
+/* expect a specified UDP payload on the OPCAP connection 'idx' */
+function f_opcap_exp_udp(octetstring udp_payload, integer idx) runs on test_CT {
+ var octetstring rx_tail;
+ var integer udp_payload_len, rx_pdu_len;
+ var OPCAP_PDU rx_pdu;
+
+ udp_payload_len := lengthof(udp_payload);
+
+ /* sadly I couldn't figure out how to create an octetstring template
+ * for 'match an octetstring ending in 'udp_payload' */
+ rx_pdu := f_opcap_exp(tr_OPCAP_PKT(?), idx);
+ rx_pdu_len := lengthof(rx_pdu.u.packet.payload);
+ rx_tail := substr(rx_pdu.u.packet.payload, rx_pdu_len - udp_payload_len, udp_payload_len);
+ if (rx_tail != udp_payload) {
+ log("captured UDP payload: ", rx_tail, " but expected: ", udp_payload);
+ setverdict(fail);
+ } else {
+ setverdict(pass);
+ }
+}
+
+/* create an additional pcap-store-connection via the VTY */
+function f_vty_create_addl_connection(integer idx) runs on test_CT
+{
+ f_vty_config3(VTY, { "client", "pcap-store-connectio second-" & int2str(idx) },
+ { "server ip " & mp_local_opcap_ip,
+ "server port " & int2str(mp_local_opcap_port + idx),
+ "connect" }
+ );
+}
+
+
+
+/* wait for inbound client connection and reception of link header */
+testcase TC_connect_rx_hdr() runs on test_CT
+{
+ f_init();
+ f_init_one_srv(0, ?);
+ setverdict(pass);
+}
+
+/* check if client connection is re-started after a close */
+testcase TC_reconnect(integer idx := 0) runs on test_CT
+{
+ f_init();
+ f_init_one_srv(idx, ?);
+ f_sleep(2.0);
+
+ log("Disconnecting client-", idx);
+ f_disconnect(idx);
+
+ f_wait_client_connect(idx);
+ f_opcap_exp(tr_OPCAP_FILE_HDR(?), idx);
+ setverdict(pass);
+}
+
+/* capture a packet that's within the filter */
+testcase TC_capture() runs on test_CT
+{
+ f_init();
+ f_init_one_srv(0, ?);
+
+ for (var integer i := 0; i < 10; i := i + 1) {
+ var octetstring udp_payload;
+
+ /* we assume 1400 is low enough to avoid IP fragmentation */
+ udp_payload := f_rnd_octstring(f_rnd_int(1400));
+ f_trafic_pkt_ab(udp_payload);
+
+ f_opcap_exp_udp(udp_payload, 0);
+ }
+}
+
+/* wait for inbound client connections and reception of link header */
+testcase TC_multi_connect_rx_hdr() runs on test_CT
+{
+ f_init();
+ f_init_one_srv(0, ?);
+ f_vty_create_addl_connection(1);
+ f_init_one_srv(1, ?);
+ setverdict(pass);
+}
+
+/* ensure a packet that's within the filter is sent to secondary clients */
+testcase TC_multi_capture() runs on test_CT
+{
+ f_init();
+ f_init_one_srv(0, ?);
+ f_vty_create_addl_connection(1);
+ f_init_one_srv(1, ?);
+
+ for (var integer i := 0; i < 10; i := i + 1) {
+ var octetstring udp_payload;
+
+ /* we assume 1400 is low enough to avoid IP fragmentation */
+ udp_payload := f_rnd_octstring(f_rnd_int(1400));
+ f_trafic_pkt_ab(udp_payload);
+
+ /* expect packet to arrive on both simulated servers */
+ f_opcap_exp_udp(udp_payload, 0);
+ f_opcap_exp_udp(udp_payload, 1);
+ }
+}
+
+/* TODO: ensure a packet outside the filter is dropped */
+/* TODO: capture of truncated packet */
+/* TODO: stall the receive window */
+/* TODO: different link type (ethernet, not SLL) */
+
+
+control {
+ execute( TC_connect_rx_hdr() );
+ execute( TC_reconnect() );
+ execute( TC_capture() );
+ execute( TC_multi_connect_rx_hdr() );
+ execute( TC_multi_capture() );
+};
+
+
+};
diff --git a/pcap-client/gen_links.sh b/pcap-client/gen_links.sh
new file mode 100755
index 0000000..e459959
--- /dev/null
+++ b/pcap-client/gen_links.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+BASEDIR=../deps
+
+. ../gen_links.sh.inc
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h"
+FILES+=" TCCEncoding_Functions.ttcn TCCEncoding.cc " # GSM 7-bit coding
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
+FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.TELNETasp/src
+FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc "
+FILES+="Osmocom_VTY_Functions.ttcn "
+FILES+="OPCAP_Types.ttcn OPCAP_Templates.ttcn "
+FILES+="OPCAP_CodecPort.ttcn OPCAP_CodecPort_CtrlFunct.ttcn OPCAP_CodecPort_CtrlFunctdef.cc OPCAP_Adapter.ttcn "
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/pcap-client/osmo-pcap-client.cfg b/pcap-client/osmo-pcap-client.cfg
new file mode 100644
index 0000000..89f1801
--- /dev/null
+++ b/pcap-client/osmo-pcap-client.cfg
@@ -0,0 +1,14 @@
+!
+! OsmoPCAPClient (UNKNOWN-dirty) configuration saved from vty
+!!
+!
+!
+line vty
+ no login
+!
+client
+ pcap device lo
+ pcap filter udp port 44423
+ pcap detect-loop 0
+ server ip 127.0.0.1
+ server port 5000
diff --git a/pcap-client/regen_makefile.sh b/pcap-client/regen_makefile.sh
new file mode 100755
index 0000000..9e4a6ee
--- /dev/null
+++ b/pcap-client/regen_makefile.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+FILES="*.ttcn TCCConversion.cc TCCInterface.cc TCCEncoding.cc IPL4asp_PT.cc IPL4asp_discovery.cc TELNETasp_PT.cc Native_FunctionDefs.cc OPCAP_CodecPort_CtrlFunctdef.cc "
+#FILES+="*.ttcnpp "
+#FILES+="*.asn"
+
+export CPPFLAGS_TTCN3=""
+
+../regen-makefile.sh OPCAP_CLIENT_Tests.ttcn $FILES
+
+#sed -i -e 's/^LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lfftranscode/' Makefile