[MERGED] osmo-ttcn3-hacks[master]: sip: Add SIP_Emulation and first osmo-sip-connector test case

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Fri Mar 23 08:31:47 UTC 2018


Harald Welte has submitted this change and it was merged.

Change subject: sip: Add SIP_Emulation and first osmo-sip-connector test case
......................................................................


sip: Add SIP_Emulation and first osmo-sip-connector test case

Change-Id: Ifd47b0d48c609b4a678ea47aa7f89f5c12e6c0d2
---
M library/MNCC_Emulation.ttcn
M library/MNCC_Types.ttcn
A library/SIP_Emulation.ttcn
A sip/SIP_Tests.cfg
A sip/SIP_Tests.default
A sip/SIP_Tests.ttcn
A sip/gen_links.sh
A sip/regen_makefile.sh
8 files changed, 769 insertions(+), 9 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/library/MNCC_Emulation.ttcn b/library/MNCC_Emulation.ttcn
index 60ec58b..856575e 100644
--- a/library/MNCC_Emulation.ttcn
+++ b/library/MNCC_Emulation.ttcn
@@ -193,7 +193,7 @@
 }
 
 
-function f_connect(charstring sock) runs on MNCC_Emulation_CT {
+private function f_connect(charstring sock) runs on MNCC_Emulation_CT {
 	var UD_connect_result res;
 	timer T := 5.0;
 
@@ -215,6 +215,40 @@
 	}
 }
 
+private function f_listen(charstring sock) runs on MNCC_Emulation_CT {
+	var UD_listen_result res;
+	var UD_connected udc;
+	timer T := 5.0;
+
+	T.start;
+	MNCC.send(UD_listen:{sock});
+	alt {
+	[] MNCC.receive(UD_listen_result:?) -> value res {
+		if (ispresent(res.result) and ispresent(res.result.result_code) and res.result.result_code == ERROR) {
+			setverdict(fail, "Error listening to MNCC socket", res);
+			self.stop;
+		} else {
+			g_mncc_ud_id := res.id;
+		}
+		}
+	[] T.timeout {
+		setverdict(fail, "Timeout listening to MNCC socket");
+		self.stop;
+		}
+	}
+
+	T.start;
+	alt {
+	[] MNCC.receive(UD_connected:?) -> value udc {
+		g_mncc_ud_id := res.id;
+		}
+	[] T.timeout {
+		setverdict(fail, "Timeout waiting for MNCC connection");
+		self.stop;
+		}
+	}
+}
+
 /* call-back type, to be provided by specific implementation; called when new SCCP connection
  * arrives */
 type function MnccCreateCallback(MNCC_PDU conn_ind, charstring id)
@@ -228,9 +262,14 @@
 	MnccUnitdataCallback unitdata_cb
 }
 
-function main(MnccOps ops, charstring id, charstring sock) runs on MNCC_Emulation_CT {
+function main(MnccOps ops, charstring id, charstring sock, boolean role_server := false)
+runs on MNCC_Emulation_CT {
 
-	f_connect(sock);
+	if (role_server) {
+		f_listen(sock);
+	} else {
+		f_connect(sock);
+	}
 	f_expect_table_init();
 	f_call_table_init();
 
@@ -289,15 +328,19 @@
 			f_call_table_del(call_id);
 			}
 
-		/* Client -> MNCC Socket: SETUP.req: forward + add call table entry */
-		[] MNCC_CLIENT.receive(MNCC_PDU:{msg_type := MNCC_SETUP_REQ, u:=?}) -> value mncc sender vc_conn {
-			/* add to call table */
-			f_call_table_add(vc_conn, f_mncc_get_call_id(mncc));
+		/* Client -> MNCC Socket: Normal message */
+		[] MNCC_CLIENT.receive(MNCC_PDU:?) -> value mncc sender vc_conn {
+			if (mncc.msg_type == MNCC_SETUP_REQ and not role_server) {
+				/* ConnHdlr -> MNCC Server: SETUP.req: add to call table */
+				f_call_table_add(vc_conn, f_mncc_get_call_id(mncc));
+			} else if (mncc.msg_type == MNCC_SETUP_IND and role_server) {
+				/* ConnHdlr -> MNCC Client: SETUP.ind: add to call table */
+				f_call_table_add(vc_conn, f_mncc_get_call_id(mncc));
+			}
 			/* forward to MNCC socket */
 			MNCC.send(t_SD_MNCC(g_mncc_ud_id, mncc));
 			}
 
-		/* Client -> MNCC Socket: Normal message */
 		[] MNCC_CLIENT.receive(MNCC_PDU:?) -> value mncc sender vc_conn {
 			/* forward to MNCC socket */
 			MNCC.send(t_SD_MNCC(g_mncc_ud_id, mncc));
diff --git a/library/MNCC_Types.ttcn b/library/MNCC_Types.ttcn
index 001b4b8..8d47efb 100644
--- a/library/MNCC_Types.ttcn
+++ b/library/MNCC_Types.ttcn
@@ -561,7 +561,38 @@
 			lchan_mode := ?
 		}
 	}
-
+}
+template (value) MNCC_PDU ts_MNCC_SETUP_ind(uint32_t call_id, MNCC_number called,
+				    template (omit) MNCC_number calling := omit,
+				    template (omit) charstring imsi := omit,
+				    template (value) MNCC_bearer_cap bcap := ts_MNCC_bcap_voice) := {
+	msg_type := MNCC_SETUP_IND,
+	u := {
+		signal := {	/* See 24.008 9.3.23.2 */
+			callref := call_id,
+			bearer_cap := valueof(bcap),			/* mandatory */
+			called := called,				/* mandatory */
+			calling := calling,				/* optional */
+			redirecting := omit,
+			connected := omit,
+			cause := omit,
+			progress := omit,
+			useruser := omit,				/* optional */
+			facility := omit,				/* optional */
+			cccap := omit,					/* optional */
+			ssversion := omit,				/* optional */
+			clir_sup := 0,					/* optional */
+			clir_inv := 0,					/* optional */
+			signal := omit,
+			keypad := omit,
+			more := 0,
+			notify := 0,
+			emergency := omit,
+			imsi := imsi,
+			lchan_type := 0,
+			lchan_mode := 0
+		}
+	}
 }
 
 /* MO: MSC <- MNCC: SETUP.cnf; Response to SETUP.ind */
diff --git a/library/SIP_Emulation.ttcn b/library/SIP_Emulation.ttcn
new file mode 100644
index 0000000..57ec704
--- /dev/null
+++ b/library/SIP_Emulation.ttcn
@@ -0,0 +1,408 @@
+module SIP_Emulation {
+
+/* SIP Emulation, runs on top of SIPmsg_PT.  It multiplexes/demultiplexes
+ * the individual calls, so there can be separate TTCN-3 components handling
+ * each of the calls
+ *
+ * The SIP_Emulation.main() function processes SIP message from the SIPmsg
+ * socket via the SIPmsg_PT, and dispatches them to the per-connection components.
+ *
+ * Outbound SIP calls are initiated by sending a PDU_SIP_Request messages
+ * to the component running the SIP_Emulation.main() function.
+ *
+ * For each new inbound call, the SipOps.create_cb() is called.  It can create
+ * or resolve a TTCN-3 component, and returns a component reference to which that inbound
+ * call is routed/dispatched.
+ *
+ * If a pre-existing component wants to register to handle a future inbound call, it can
+ * do so by registering an "expect" with the expected destination phone number.  This is e.g. useful
+ * if you are simulating MNCC + SIP, and first trigger a connection from MNCC side in a
+ * component which then subsequently should also handle the SIP emulation.
+ *
+ * (C) 2018 by Harald Welte <laforge at gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ */
+
+import from SIPmsg_Types all;
+import from SIPmsg_PortType all;
+
+type component SIP_ConnHdlr {
+	/* ports towards SIP Emulation core / call dispatcher */
+	port SIP_Conn_PT SIP;
+	port SIPEM_PROC_PT SIP_PROC;
+}
+
+/* port between individual per-call components and this dispatcher */
+type port SIP_Conn_PT message {
+	inout PDU_SIP_Request, PDU_SIP_Response;
+} with { extension "internal" };
+
+/* represents a single SIP Call */
+type record CallData {
+	/* reference to the instance of the per-connection component */
+	SIP_ConnHdlr	comp_ref,
+	CallidString	call_id
+}
+
+type component SIP_Emulation_CT {
+	/* SIP test port on bottom side */
+	port SIPmsg_PT SIP;
+	/* SIP port to the per-call clients */
+	port SIP_Conn_PT CLIENT;
+
+	var CallData SipCallTable[16];
+	var ExpectData SipExpectTable[16];
+
+	/* procedure based port to register for incoming connections */
+	port SIPEM_PROC_PT CLIENT_PROC;
+};
+
+private function f_sip_init() runs on SIP_Emulation_CT {
+	map(self:SIP, system:SIP);
+}
+
+template RequestLine tr_ReqLine(template Method method) := {
+	method := method,
+	requestUri := ?,
+	sipVersion := ?
+}
+
+template PDU_SIP_Request tr_SIP_INVITE := {
+	requestLine := tr_ReqLine(INVITE_E),
+	msgHeader := t_SIP_msgHeader_any,
+	messageBody := *,
+	payload := *
+}
+
+
+template SipUrl tr_SIP_Url(template charstring user_or_num,
+			   template charstring host := *,
+			   template integer portField := *) := {
+	scheme := "sip",
+	userInfo := {
+		userOrTelephoneSubscriber := user_or_num,
+		password := *
+	},
+	hostPort := {
+		host := host,
+		portField := portField
+	},
+	urlParameters := *,
+	headers := *
+}
+template (value) SipUrl ts_SIP_Url(charstring user_or_num,
+			   template (omit) charstring host := omit,
+			   template (omit) integer portField := omit) := {
+	scheme := "sip",
+	userInfo := {
+		userOrTelephoneSubscriber := user_or_num,
+		password := omit
+	},
+	hostPort := {
+		host := host,
+		portField := portField
+	},
+	urlParameters := omit,
+	headers := omit
+}
+
+template Addr_Union tr_SIP_Addr(template SipUrl sip_url) := {
+	nameAddr := {
+		displayName := *,
+		addrSpec := sip_url
+	}
+}
+template (value) Addr_Union ts_SIP_Addr(template (value) SipUrl sip_url) := {
+	nameAddr := {
+		displayName := omit,
+		addrSpec := sip_url
+	}
+}
+
+template To tr_SIP_To(template Addr_Union addr) := {
+	fieldName := TO_E,
+	addressField := addr,
+	toParams := *
+}
+template (value) To ts_SIP_To(template (value) Addr_Union addr) := {
+	fieldName := TO_E,
+	addressField := addr,
+	toParams := omit
+}
+
+/* resolve component reference by connection ID */
+private function f_call_id_known(CallidString call_id)
+runs on SIP_Emulation_CT return boolean {
+	var integer i;
+	for (i := 0; i < sizeof(SipCallTable); i := i+1) {
+		if (SipCallTable[i].call_id == call_id) {
+			return true;
+		}
+	}
+	return false;
+}
+
+/* resolve component reference by connection ID */
+private function f_comp_by_call_id(CallidString call_id)
+runs on SIP_Emulation_CT return SIP_ConnHdlr {
+	var integer i;
+	for (i := 0; i < sizeof(SipCallTable); i := i+1) {
+		if (SipCallTable[i].call_id == call_id) {
+			return SipCallTable[i].comp_ref;
+		}
+	}
+	setverdict(fail, "SIP Call table not found by SIP Call ID ", call_id);
+	self.stop;
+}
+
+/* resolve connection ID by component reference */
+private function f_call_id_by_comp(SIP_ConnHdlr client)
+runs on SIP_Emulation_CT return CallidString {
+	for (var integer i := 0; i < sizeof(SipCallTable); i := i+1) {
+		if (SipCallTable[i].comp_ref == client) {
+			return SipCallTable[i].call_id;
+		}
+	}
+	setverdict(fail, "SIP Call table not found by component ", client);
+	self.stop;
+}
+
+private function f_expect_table_init()
+runs on SIP_Emulation_CT {
+	for (var integer i := 0; i < sizeof(SipExpectTable); i := i+1) {
+		SipExpectTable[i].sip_to := omit;
+		SipExpectTable[i].vc_conn := null;
+	}
+}
+
+private function f_call_table_init()
+runs on SIP_Emulation_CT {
+	for (var integer i := 0; i < sizeof(SipCallTable); i := i+1) {
+		SipCallTable[i].comp_ref := null;
+		SipCallTable[i].call_id := "";
+	}
+}
+
+private function f_call_table_add(SIP_ConnHdlr comp_ref, CallidString call_id)
+runs on SIP_Emulation_CT {
+	for (var integer i := 0; i < sizeof(SipCallTable); i := i+1) {
+		if (SipCallTable[i].call_id == "") {
+			SipCallTable[i].comp_ref := comp_ref;
+			SipCallTable[i].call_id := call_id;
+			log("Added SIP Call Table entry [", i, "] for ", call_id, " at ", comp_ref);
+			return;
+		}
+	}
+	setverdict(fail, "SIP Call table full");
+	self.stop;
+}
+
+private function f_call_table_del(CallidString call_id)
+runs on SIP_Emulation_CT {
+	for (var integer i := 0; i < sizeof(SipCallTable); i := i+1) {
+		if (SipCallTable[i].call_id == call_id) {
+			SipCallTable[i].comp_ref := null;
+			SipCallTable[i].call_id := "";
+			log("Deleted SIP Call Table entry [", i, "] for ", call_id);
+			return;
+		}
+	}
+	setverdict(fail, "SIP Call table attempt to delete non-existant ", call_id);
+	self.stop;
+}
+
+/* call-back type, to be provided by specific implementation; called when new call connection
+ * arrives */
+type function SipCreateCallback(PDU_SIP_Request sip_req, charstring id)
+runs on SIP_Emulation_CT return SIP_ConnHdlr;
+
+type record SipOps {
+	SipCreateCallback create_cb
+};
+
+function f_init_sip(inout SIP_Emulation_CT ct, charstring id) {
+	id := id & "-SIP";
+
+	var SipOps ops := {
+		create_cb := refers(SIP_Emulation.ExpectedCreateCallback)
+	};
+
+	ct := SIP_Emulation_CT.create(id);
+	map(ct:SIP, system:SIP);
+	ct.start(SIP_Emulation.main(ops, id));
+}
+
+function main(SipOps ops, charstring id)
+runs on SIP_Emulation_CT {
+
+	f_sip_init();
+	f_expect_table_init();
+	f_call_table_init();
+
+	while (true) {
+		var SIP_ConnHdlr vc_hdlr, vc_conn;
+		var PDU_SIP_Request sip_req;
+		var PDU_SIP_Response sip_resp;
+		var SipUrl sip_to;
+
+		alt {
+		/* SIP INVITE was received on SIP socket/port */
+		[] SIP.receive(tr_SIP_INVITE) -> value sip_req {
+			var CallidString call_id := sip_req.msgHeader.callId.callid;
+			if (f_call_id_known(call_id)) {
+				/* re-invite? */
+				vc_conn := f_comp_by_call_id(call_id);
+			} else {
+				/* new INVITE: check expect */
+				vc_conn := ops.create_cb.apply(sip_req, id);
+				f_call_table_add(vc_conn, call_id);
+			}
+			CLIENT.send(sip_req) to vc_conn;
+			}
+		/* other SIP request was received on SIP socket/port */
+		[] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
+			var CallidString call_id := sip_req.msgHeader.callId.callid;
+			if (f_call_id_known(call_id)) {
+				vc_conn := f_comp_by_call_id(call_id);
+				CLIENT.send(sip_req) to vc_conn;
+			} else {
+				setverdict(fail, "SIP Request for unknown call ", call_id);
+				self.stop;
+			}
+			}
+		/* SIP response was received on SIP socket/port */
+		[] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
+			var CallidString call_id := sip_resp.msgHeader.callId.callid;
+			if (f_call_id_known(call_id)) {
+				vc_conn := f_comp_by_call_id(call_id);
+				CLIENT.send(sip_resp) to vc_conn;
+			} else {
+				setverdict(fail, "SIP Response for unknown call ", call_id);
+				self.stop;
+			}
+			}
+
+		/* a ConnHdlr is sending us a SIP INVITE: Forward to SIP port */
+		[] CLIENT.receive(tr_SIP_INVITE) -> value sip_req sender vc_conn {
+			var CallidString call_id := sip_req.msgHeader.callId.callid;
+			if (f_call_id_known(call_id)) {
+				/* re-invite? */
+				vc_conn := f_comp_by_call_id(call_id);
+			} else {
+				/* new INVITE: add to table */
+				f_call_table_add(vc_conn, call_id);
+			}
+			SIP.send(sip_req);
+			}
+		/* a ConnHdlr is sending us a SIP request: Forward to SIP port */
+		[] CLIENT.receive(PDU_SIP_Request:?) -> value sip_req sender vc_conn {
+			SIP.send(sip_req);
+			}
+		/* a ConnHdlr is sending us a SIP request: Forward to SIP port */
+		[] CLIENT.receive(PDU_SIP_Response:?) -> value sip_resp sender vc_conn {
+			SIP.send(sip_resp);
+			}
+
+		[] CLIENT_PROC.getcall(SIPEM_register:{?,?}) -> param(sip_to, vc_hdlr) {
+			f_create_expect(sip_to, vc_hdlr);
+			CLIENT_PROC.reply(SIPEM_register:{sip_to, vc_hdlr});
+			}
+
+		}
+	}
+}
+
+/***********************************************************************
+ * "Expect" Handling (mapping for expected incoming SIP callds from IUT)
+ ***********************************************************************/
+
+/* data about an expected future incoming connection */
+type record ExpectData {
+	/* SIP "To" (destination number) based on which we can match */
+	SipUrl sip_to optional,
+	/* component reference registered for the connection */
+	SIP_ConnHdlr vc_conn
+}
+
+/* procedure based port to register for incoming calls */
+signature SIPEM_register(SipUrl sip_to, SIP_ConnHdlr vc_conn);
+
+type port SIPEM_PROC_PT procedure {
+	inout SIPEM_register;
+} with { extension "internal" };
+
+
+/* CreateCallback that can be used as create_cb and will use the expect table */
+function ExpectedCreateCallback(PDU_SIP_Request sip_req, charstring id)
+runs on SIP_Emulation_CT return SIP_ConnHdlr {
+	var SIP_ConnHdlr ret := null;
+	var SipUrl sip_to;
+	var integer i;
+
+	if (sip_req.requestLine.method != INVITE_E) {
+		setverdict(fail, "SIP ExpectedCreateCallback needs INVITE");
+		return ret;
+	}
+	sip_to := sip_req.msgHeader.toField.addressField.nameAddr.addrSpec;
+
+	for (i := 0; i < sizeof(SipExpectTable); i := i+1) {
+		if (not ispresent(SipExpectTable[i].sip_to)) {
+			continue;
+		}
+		/* build a template, use '*' for all 'omit' values */
+		var template SipUrl t_exp := SipExpectTable[i].sip_to;
+		if (not ispresent(t_exp.hostPort.host)) {
+			t_exp.hostPort.host := *;
+		}
+		if (not ispresent(t_exp.hostPort.portField)) {
+			t_exp.hostPort.portField := *;
+		}
+		if (not ispresent(t_exp.urlParameters)) {
+			t_exp.urlParameters := *;
+		}
+		if (not ispresent(t_exp.headers)) {
+			t_exp.headers := *;
+		}
+		/* match against the constructed template */
+		if (match(sip_to, t_exp)) {
+			ret := SipExpectTable[i].vc_conn;
+			/* release this entry to be used again */
+			SipExpectTable[i].sip_to := omit;
+			SipExpectTable[i].vc_conn := null;
+			log("Found SipExpect[", i, "] for ", sip_to, " handled at ", ret);
+			return ret;
+		}
+	}
+
+	setverdict(fail, "Couldn't find SipExpect for incoming call ", sip_to);
+	return ret;
+}
+
+/* server/emulation side function to create expect */
+private function f_create_expect(SipUrl sip_to, SIP_ConnHdlr hdlr)
+runs on SIP_Emulation_CT {
+	var integer i;
+	for (i := 0; i < sizeof(SipExpectTable); i := i+1) {
+		if (not ispresent(SipExpectTable[i].sip_to)) {
+			SipExpectTable[i].sip_to := sip_to;
+			SipExpectTable[i].vc_conn := hdlr;
+			log("Created SipExpect[", i, "] for ", sip_to, " to be handled at ", hdlr);
+			return;
+		}
+	}
+	setverdict(fail, "No space left in SipExpectTable");
+}
+
+/* client/conn_hdlr side function to use procedure port to create expect in emulation */
+function f_create_sip_expect(SipUrl sip_to) runs on SIP_ConnHdlr {
+	SIP_PROC.call(SIPEM_register:{sip_to, self}) {
+		[] SIP_PROC.getreply(SIPEM_register:{?,?}) {};
+	}
+}
+
+
+
+}
diff --git a/sip/SIP_Tests.cfg b/sip/SIP_Tests.cfg
new file mode 100644
index 0000000..db435af
--- /dev/null
+++ b/sip/SIP_Tests.cfg
@@ -0,0 +1,18 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./SIP_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+SIP_Tests.control
diff --git a/sip/SIP_Tests.default b/sip/SIP_Tests.default
new file mode 100644
index 0000000..b0abf18
--- /dev/null
+++ b/sip/SIP_Tests.default
@@ -0,0 +1,30 @@
+[LOGGING]
+FileMask := LOG_ALL | TTCN_MATCHING;
+
+"IPA-CTRL-IPA".FileMask := ERROR | WARNING;
+mtc.FileMask := ERROR | WARNING;
+
+[TESTPORT_PARAMETERS]
+"SIP_Test-MNCC".MNCC.socket_type := "SEQPACKET";
+*.SIPVTY.CTRL_MODE := "client"
+*.SIPVTY.CTRL_HOSTNAME := "127.0.0.1"
+*.SIPVTY.CTRL_PORTNUM := "4256"
+*.SIPVTY.CTRL_LOGIN_SKIPPED := "yes"
+*.SIPVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes"
+*.SIPVTY.CTRL_READMODE := "buffered"
+*.SIPVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
+*.SIPVTY.PROMPT1 := "OsmoMNCC> "
+
+*.SIP.local_sip_port := "5060"
+*.SIP.default_local_address := "127.0.0.2"
+*.SIP.default_sip_protocol := "UDP"
+*.SIP.default_dest_port := "5060"
+*.SIP.default_dest_address := "127.0.0.1"
+
+
+[MODULE_PARAMETERS]
+Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoMNCC";
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
diff --git a/sip/SIP_Tests.ttcn b/sip/SIP_Tests.ttcn
new file mode 100644
index 0000000..de2f498
--- /dev/null
+++ b/sip/SIP_Tests.ttcn
@@ -0,0 +1,173 @@
+module SIP_Tests {
+
+import from General_Types all;
+import from Osmocom_Types all;
+
+import from Osmocom_CTRL_Functions all;
+import from Osmocom_CTRL_Types all;
+import from Osmocom_CTRL_Adapter all;
+
+import from TELNETasp_PortType all;
+import from Osmocom_VTY_Functions all;
+
+import from MNCC_Emulation all;
+import from MNCC_Types all;
+
+import from SDP_Types all;
+
+import from SIP_Emulation all;
+import from SIPmsg_Types all;
+
+modulepar {
+	//charstring mp_local_host := "127.0.0.2;
+	charstring mp_osmosip_host := "127.0.0.1";
+	integer mp_osmosip_port_ctrl := -1; /* RFU */
+	charstring mp_mncc := "/tmp/mncc";
+}
+
+type component test_CT extends CTRL_Adapter_CT {
+	var MNCC_Emulation_CT vc_MNCC;
+	var SIP_Emulation_CT vc_SIP;
+
+	port TELNETasp_PT SIPVTY;
+}
+
+type component ConnHdlr extends SIP_ConnHdlr, MNCC_ConnHdlr {
+	var ConnHdlrPars g_pars;
+	timer g_Tguard;
+}
+
+type record ConnHdlrPars {
+	float t_guard
+}
+
+
+function f_init_mncc(charstring id) runs on test_CT {
+	id := id & "-MNCC";
+	var MnccOps ops := {
+		create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
+		unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback)
+	};
+
+	vc_MNCC := MNCC_Emulation_CT.create(id);
+	map(vc_MNCC:MNCC, system:MNCC_CODEC_PT);
+	vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_mncc, true));
+}
+
+function f_init() runs on test_CT {
+	//f_ipa_ctrl_start(mp_osmosip_host, mp_osmosip_port_ctrl);
+	f_init_mncc("SIP_Test");
+	log("end of f_init_mncc");
+	f_init_sip(vc_SIP, "SIP_Test");
+	log("end of f_init_sip");
+
+	map(self:SIPVTY, system:SIPVTY);
+	f_vty_set_prompts(SIPVTY);
+	f_vty_transceive(SIPVTY, "enable");
+	log("end of f_init");
+}
+
+type function void_fn(charstring id) runs on ConnHdlr;
+
+function f_start_handler(void_fn fn, ConnHdlrPars pars)
+runs on test_CT return ConnHdlr {
+	var ConnHdlr vc_conn;
+	var charstring id := testcasename();
+
+	vc_conn := ConnHdlr.create(id);
+
+	connect(vc_conn:SIP, vc_SIP:CLIENT);
+	connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
+
+	connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT);
+	connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC);
+
+	vc_conn.start(f_handler_init(fn, id, pars));
+	return vc_conn;
+}
+
+private altstep as_Tguard() runs on ConnHdlr {
+	[] g_Tguard.timeout {
+		setverdict(fail, "Tguard timeout");
+		self.stop;
+	}
+}
+
+private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
+runs on ConnHdlr {
+	g_pars := pars;
+	g_Tguard.start(pars.t_guard);
+	activate(as_Tguard());
+
+	/* call the user-supied test case function */
+	fn.apply(id);
+}
+
+
+template (value) ConnHdlrPars t_Pars := {
+	t_guard := 30.0
+}
+
+private function f_TC_mo_setup(charstring id) runs on ConnHdlr {
+	var PDU_SIP_Request sip_req;
+
+	var MNCC_number dst := valueof(ts_MNCC_number("01234567"));
+	var MNCC_number src := valueof(ts_MNCC_number("112"));
+
+	f_create_sip_expect(valueof(ts_SIP_Url("+01234567")));
+
+	log("sending mncc setup");
+	MNCC.send(ts_MNCC_SETUP_ind(2342, dst, src, "262420123456789"));
+
+	MNCC.receive(tr_MNCC_RTP_CREATE(2342));
+	MNCC.send(ts_MNCC_RTP_CREATE(2342));
+
+	SIP.receive(PDU_SIP_Request:?) -> value sip_req {
+		log(sip_req);
+	}
+}
+
+testcase TC_mo_setup() runs on test_CT {
+	var ConnHdlrPars pars;
+	var ConnHdlr vc_conn;
+
+	f_init();
+
+	pars := valueof(t_Pars);
+	vc_conn := f_start_handler(refers(f_TC_mo_setup), pars);
+	vc_conn.done;
+}
+
+
+
+
+
+/* SIP specifics */
+
+const integer c_SIP_PORT := 5060;
+
+template (value) SIP_comm_adress ts_SipAddr(charstring rhost,
+					    template (omit) charstring lhost := omit,
+					    integer rport := c_SIP_PORT,
+					    integer lport := c_SIP_PORT,
+					    SIP_com_prot prot := UDP_E) := {
+	remote_host := rhost,
+	remote_port := rport,
+	local_host := lhost,
+	local_port := lport,
+	protocol := prot
+}
+
+template (value) ASP_SIP_open ts_SIP_open(SIP_comm_adress addr) := {
+	addr := addr
+}
+
+
+
+control {
+	execute( TC_mo_setup() );
+}
+
+
+
+}
diff --git a/sip/gen_links.sh b/sip/gen_links.sh
new file mode 100755
index 0000000..ff64056
--- /dev/null
+++ b/sip/gen_links.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+BASEDIR=../deps
+
+. ../gen_links.sh.inc
+
+DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src
+FILES="UD_PT.cc  UD_PT.hh  UD_PortType.ttcn  UD_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+# Required by MGCP and IPA
+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.ProtocolModules.SDP/src
+FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l
+SDP_parser.y lex.SDP_parse_.c"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.RTP/src
+FILES="RTP_EncDec.cc RTP_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.SIPmsg/src
+FILES="SIP_parse.h SIP_parse.y SIP_parse_.tab.h SIPmsg_PT.hh SIPmsg_Types.ttcn SIP_parse.l SIP_parse_.tab.c SIPmsg_PT.cc SIPmsg_PortType.ttcn lex.SIP_parse_.c"
+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="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn MNCC_Types.ttcn MNCC_EncDec.cc MNCC_CodecPort.ttcn mncc.h MNCC_Emulation.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc "
+FILES+="IPA_Types.ttcn IPA_Emulation.ttcnpp IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc "
+FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn "
+FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc "
+FILES+="SIP_Emulation.ttcn "
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/sip/regen_makefile.sh b/sip/regen_makefile.sh
new file mode 100755
index 0000000..86f71b8
--- /dev/null
+++ b/sip/regen_makefile.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+FILES="*.ttcn *.ttcnpp TCCConversion.cc TCCInterface.cc UD_PT.cc MNCC_EncDec.cc IPL4asp_PT.cc
+IPL4asp_discovery.cc SDP_EncDec.cc RTP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc RTP_CodecPort_CtrlFunctDef.cc TELNETasp_PT.cc Native_FunctionDefs.cc SIPmsg_PT.cc *.c "
+
+export CPPFLAGS_TTCN3=""
+
+../regen-makefile.sh SIP_Tests.ttcn $FILES

-- 
To view, visit https://gerrit.osmocom.org/7465
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ifd47b0d48c609b4a678ea47aa7f89f5c12e6c0d2
Gerrit-PatchSet: 1
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder



More information about the gerrit-log mailing list