commit 92d1d7d2abcc66351db56f839533eb2971915164 Author: Harald Welte Date: Thu Jul 2 18:24:07 2020 +0200 initial checkin of Osmocom E1TS (E1 timeslot) test port for TITAN Change-Id: Ib03a6a5b3d7e4864bf797e4a69b87a64515dd953 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1bba67a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.d +*.so +compile diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3534f2f --- /dev/null +++ b/LICENSE @@ -0,0 +1,277 @@ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..111e0da --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +titan.TestPorts.E1TS +==================== + +This implements a TTCN-3 E1 Timeslot test port for Eclipse TITAN. Running on a (Linux) computer, +it allows you to write TTCN-3 tests sending and receiving data on 64kBps E1 timeslots. + +In order to interface both physical and virtual E1 lines, this port currently relies on +osmo-e1d, the Osmocom E1 daemon [1]. Adding back-ends for other drivers such as DAHDI should +not be hard, if needed at a later point. + +The timeslots can either be opened in RAW (transparent) 64kBps mode, or with a HDLC controller. + +The idea of this module is to be able to write abstract test suites in TTCN-3 which interface +IUT (Implementations under Test) over E1. + + +GIT repository +-------------- + +You can clone from the official titan.TestPorts.E1TS repository using + + git clone https://git.osmocom.org/titan.TestPorts.E1TS + +There's a cgit interface at + +Documentation +------------- + +This is still very much a Work-In-Progress, and hence there's no documentation yet, sorry. + +References +---------- + +[1] osmo-e1d homepage at https://osmocom.org/projects/osmo-e1d/wiki diff --git a/example/E1TS_PT.cc b/example/E1TS_PT.cc new file mode 120000 index 0000000..6db7ab4 --- /dev/null +++ b/example/E1TS_PT.cc @@ -0,0 +1 @@ +../src/E1TS_PT.cc \ No newline at end of file diff --git a/example/E1TS_PT.hh b/example/E1TS_PT.hh new file mode 120000 index 0000000..7a5df55 --- /dev/null +++ b/example/E1TS_PT.hh @@ -0,0 +1 @@ +../src/E1TS_PT.hh \ No newline at end of file diff --git a/example/E1TS_PortType.ttcn b/example/E1TS_PortType.ttcn new file mode 120000 index 0000000..b30bdda --- /dev/null +++ b/example/E1TS_PortType.ttcn @@ -0,0 +1 @@ +../src/E1TS_PortType.ttcn \ No newline at end of file diff --git a/example/E1TS_PortTypes.ttcn b/example/E1TS_PortTypes.ttcn new file mode 120000 index 0000000..049f24c --- /dev/null +++ b/example/E1TS_PortTypes.ttcn @@ -0,0 +1 @@ +../src/E1TS_PortTypes.ttcn \ No newline at end of file diff --git a/example/E1TS_Test.ttcn b/example/E1TS_Test.ttcn new file mode 100644 index 0000000..5bed3e4 --- /dev/null +++ b/example/E1TS_Test.ttcn @@ -0,0 +1,42 @@ +module E1TS_Test { + +import from E1TS_PortType all; +import from E1TS_PortTypes all; + +type component test_CT { + port E1TS_PT E1; +} + +testcase TC_selftest() runs on test_CT { + map(self:E1, system:E1); + var template (value) E1TS_identity ts_id := ts_E1TS_ID(0,0,2); + + E1.send(ts_E1TS_open(23, ts_id, E1TS_MODE_RAW, "e1d")); + E1.receive(tr_E1TS_result(23, 0)); + + var integer rx_count := 0, rx_bytes := 0; + var E1TS_unitdata rx_ud; + timer T := 5.0; + T.start; + while (true) { + alt { + [] E1.receive(tr_E1TS_unitdata(ts_id,?)) -> value rx_ud { + rx_bytes := rx_bytes + lengthof(rx_ud.data); + rx_count := rx_count + 1; + repeat; + } + [] T.timeout { + log(rx_count, " messages received, total bytes ", rx_bytes); + mtc.stop + }; + } + } +} + +control { + execute( TC_selftest() ); +} + + + +} diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..8028ef2 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,241 @@ +# This Makefile was generated by the Makefile Generator +# of the TTCN-3 Test Executor version CRL 113 200/6 R6B +# for Harald Welte (laforge@nataraja) on Thu Jul 2 18:32:11 2020 + +# Copyright (c) 2000-2019 Ericsson Telecom AB + +# The following make commands are available: +# - make, make all Builds the executable test suite. +# - make archive Archives all source files. +# - make check Checks the semantics of TTCN-3 and ASN.1modules. +# - make port Generates port skeletons. +# - make clean Removes all generated files. +# - make compile Translates TTCN-3 and ASN.1 modules to C++. +# - make dep Creates/updates dependency list. +# - make executable Builds the executable test suite. +# - make library Builds the library archive. +# - make objects Builds the object files without linking the executable. +# - make shared_objects Builds the shared object files without linking the executable. +# - make preprocess Preprocess TTCN-3 files. +# WARNING! This Makefile can be used with GNU make only. +# Other versions of make may report syntax errors in it. + +# +# Do NOT touch this line... +# +.PHONY: all shared_objects executable library objects check port clean dep archive preprocess + +.SUFFIXES: .d + +# +# Set these variables... +# + +ifndef TTCN3_DIR +ifneq (,$(wildcard /usr/include/titan/)) +TTCN3_DIR = /usr +TTCN3_SUBDIR = /titan +else +TTCN3_DIR = /usr +TTCN3_SUBDIR = +endif +endif + +# Your platform: (SOLARIS, SOLARIS8, LINUX, FREEBSD or WIN32) +PLATFORM = LINUX + +# Your C++ compiler: +# (if you change the platform, you may need to change the compiler) +CXX = env CCACHE_SLOPPINESS=time_macros ccache g++ + +# C preprocessor used for TTCN-3 files: +CPP = cpp + +# Flags for the C++ preprocessor (and makedepend as well): +CPPFLAGS = -D$(PLATFORM) -DMAKEDEPEND_RUN -DUSE_SCTP -I$(TTCN3_DIR)/include$(TTCN3_SUBDIR) $(shell pkg-config --cflags libosmo-e1d libosmocore) + +# Flags for dependency generation +CXXDEPFLAGS = -MM + +# Flags for preprocessing TTCN-3 files: +CPPFLAGS_TTCN3 = $(shell pkg-config --cflags libosmo-e1d libosmocore) + +# Flags for the C++ compiler: +CXXFLAGS = -fPIC + +# Flags for the linker: +LDFLAGS = -L /usr/lib/titan -fPIC + +ifeq ($(PLATFORM), WIN32) +# Silence linker warnings. +LDFLAGS += -Wl,--enable-auto-import,--enable-runtime-pseudo-reloc +endif + +# Utility to create library files +AR = ar +ARFLAGS = + +# Flags for the TTCN-3 and ASN.1 compiler: +COMPILER_FLAGS = -L -U 5 -D + +# Execution mode: (either ttcn3 or ttcn3-parallel) +TTCN3_LIB = ttcn3-parallel-dynamic + +# The path of your libxml2 installation: +# If you do not have your own one, leave it unchanged. +XMLDIR = $(TTCN3_DIR) + +# Directory to store the archived source files: +ARCHIVE_DIR = backup + +# +# You may change these variables. Add your files if necessary... +# + +# TTCN-3 modules of this project: +TTCN3_MODULES = E1TS_Test.ttcn E1TS_PortType.ttcn E1TS_PortTypes.ttcn + +# TTCN-3 modules to preprocess: +TTCN3_PP_MODULES = + +# Files to include in TTCN-3 preprocessed modules: +TTCN3_INCLUDES = + +# ASN.1 modules of this project: +ASN1_MODULES = + +# TTCN-3 source files generated by the C preprocessor: +PREPROCESSED_TTCN3_MODULES = + +# C++ source & header files generated from the TTCN-3 & ASN.1 modules of +# this project: +GENERATED_SOURCES = $(TTCN3_MODULES:.ttcn=.cc) E1TS_Test_part_1.cc E1TS_Test_part_2.cc E1TS_Test_part_3.cc E1TS_Test_part_4.cc E1TS_PortType_part_1.cc E1TS_PortType_part_2.cc E1TS_PortType_part_3.cc E1TS_PortType_part_4.cc E1TS_PortTypes_part_1.cc E1TS_PortTypes_part_2.cc E1TS_PortTypes_part_3.cc E1TS_PortTypes_part_4.cc $(TTCN3_PP_MODULES:.ttcnpp=.cc) $(ASN1_MODULES:.asn=.cc) +GENERATED_HEADERS = $(TTCN3_MODULES:.ttcn=.hh) $(TTCN3_PP_MODULES:.ttcnpp=.hh) $(ASN1_MODULES:.asn=.hh) + +# C/C++ Source & header files of Test Ports, external functions and +# other modules: +USER_SOURCES = E1TS_PT.cc +USER_HEADERS = $(USER_SOURCES:.cc=.hh) + +# Shared object files of this project: +SHARED_OBJECTS = $(GENERATED_SOURCES:.cc=.so) $(USER_SOURCES:.cc=.so) + +# Object files of this project that are needed for the executable test suite: +OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS) + +GENERATED_OBJECTS = $(GENERATED_SOURCES:.cc=.o) + +USER_OBJECTS = $(USER_SOURCES:.cc=.o) + +DEPFILES = $(USER_OBJECTS:.o=.d) $(GENERATED_OBJECTS:.o=.d) + +# Other files of the project (Makefile, configuration files, etc.) +# that will be added to the archived source files: +OTHER_FILES = Makefile + +# The name of the executable test suite: +EXECUTABLE = E1TS_Test + + + +LIBRARY = lib$(EXECUTABLE).so + +TARGET = $(EXECUTABLE) + +# +# Do not modify these unless you know what you are doing... +# Platform specific additional libraries: +# +SOLARIS_LIBS = -lsocket -lnsl -lxml2 +SOLARIS8_LIBS = -lsocket -lnsl -lxml2 +LINUX_LIBS = -lxml2 $(shell pkg-config --libs libosmo-e1d libosmocore) +FREEBSD_LIBS = -lxml2 +WIN32_LIBS = -lxml2 + +# +# Rules for building the executable... +# + +all: $(TARGET) ; + +shared_objects: $(SHARED_OBJECTS) ; + +executable: $(EXECUTABLE) ; + +library: $(LIBRARY) ; + +objects: $(OBJECTS) compile; + +$(EXECUTABLE): $(SHARED_OBJECTS) + if $(CXX) $(LDFLAGS) -o $@ -Wl,--no-as-needed $^ \ + -L$(TTCN3_DIR)/lib$(TTCN3_SUBDIR) -l$(TTCN3_LIB) \ + -L$(OPENSSL_DIR)/lib -lcrypto \ + -L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \ + then : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi + +$(LIBRARY): $(OBJECTS) + $(CXX) -shared -o $@ $(OBJECTS) + +.cc.o .c.o: + $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $< + +.cc.d .c.d: + @echo Creating dependency file for '$<'; set -e; \ + $(CXX) $(CXXDEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +%.so: %.o + $(CXX) -shared -o $@ $< + +%.ttcn: %.ttcnpp $(TTCN3_INCLUDES) + $(CPP) -x c -nostdinc $(CPPFLAGS_TTCN3) $< $@ + +preprocess: $(PREPROCESSED_TTCN3_MODULES) ; + +$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile + @if [ ! -f $@ ]; then $(RM) compile; $(MAKE) compile; fi + +check: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) + $(TTCN3_DIR)/bin/ttcn3_compiler -s $(COMPILER_FLAGS) $^ + +port: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) + $(TTCN3_DIR)/bin/ttcn3_compiler -t $(COMPILER_FLAGS) $^ + +compile: $(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES) + $(TTCN3_DIR)/bin/ttcn3_compiler $(COMPILER_FLAGS) $^ - $? + touch $@ + +clean: + -$(RM) $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \ + $(GENERATED_SOURCES) $(SHARED_OBJECTS) $(PREPROCESSED_TTCN3_MODULES) compile $(DEPFILES) \ + tags *.log + +dep: $(GENERATED_SOURCES) $(USER_SOURCES) ; + +ifeq ($(findstring n,$(MAKEFLAGS)),) +ifeq ($(filter clean check port compile archive diag preprocess,$(MAKECMDGOALS)),) +-include $(DEPFILES) +endif +endif + +archive: + mkdir -p $(ARCHIVE_DIR) + tar -cvhf - $(TTCN3_MODULES) $(TTCN3_PP_MODULES) \ + $(TTCN3_INCLUDES) $(ASN1_MODULES) \ + $(USER_HEADERS) $(USER_SOURCES) $(OTHER_FILES) \ + | gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-`date '+%y%m%d-%H%M'`.tgz + +diag: + $(TTCN3_DIR)/bin/ttcn3_compiler -v 2>&1 + $(TTCN3_DIR)/bin/mctr_cli -v 2>&1 + $(CXX) -v 2>&1 + @echo TTCN3_DIR=$(TTCN3_DIR) + @echo OPENSSL_DIR=$(OPENSSL_DIR) + @echo XMLDIR=$(XMLDIR) + @echo PLATFORM=$(PLATFORM) + +# +# Add your rules here if necessary... +# + diff --git a/src/E1TS_PT.cc b/src/E1TS_PT.cc new file mode 100644 index 0000000..9bb7dc4 --- /dev/null +++ b/src/E1TS_PT.cc @@ -0,0 +1,285 @@ +/* Copyright (c) 2020 Harald Welte */ + +#include + +#include "E1TS_PT.hh" +#include "E1TS_PortType.hh" + +extern "C" { +#include +} + +#include +#include + +using namespace E1TS__PortTypes; + +namespace E1TS__PortType { + +/* somehow std::map() won't work wit E1TS_identity as key */ +DerivedId::DerivedId(const E1TS__identity &id) +{ + interface_nr = id.interface__nr(); + line_nr = id.line__nr(); + ts_nr = id.ts__nr(); +} + +bool operator<(const DerivedId &fk, const DerivedId &lk) { + if (fk.interface_nr < lk.interface_nr) + return true; + else if (fk.interface_nr == lk.interface_nr) { + if (fk.line_nr < lk.line_nr) + return true; + else if (fk.line_nr == lk.line_nr) { + if (fk.ts_nr < lk.line_nr) + return true; + } + } + return false; +} + + +QueueEntry::QueueEntry(const uint8_t *pdata, unsigned int plen): + len(plen) +{ + data = (uint8_t *) malloc(len); + memcpy(data, pdata, len); +} + +QueueEntry::~QueueEntry() +{ + free(data); +} + +E1_Timeslot::E1_Timeslot(E1TS__PT_PROVIDER &pt, E1TS__identity id, E1TS__mode mode, int fd) + : m_pt(pt), m_id(id), m_mode(mode), m_fd(fd) +{ + m_pt.log("creating %d:%d:%d fd=%d", + (int)m_id.interface__nr(), (int)m_id.line__nr(), (int)m_id.ts__nr(), m_fd); +} + +E1_Timeslot::~E1_Timeslot() +{ + m_pt.log("destroying %d:%d:%d fd=%d", + (int)m_id.interface__nr(), (int)m_id.line__nr(), (int)m_id.ts__nr(), m_fd); + + close(m_fd); + + /* iterate over tx-queue and free all elements */ + while (!m_tx_queue.empty()) { + struct QueueEntry *qe = m_tx_queue.front(); + printf("qe=%p\n", qe); + m_tx_queue.pop(); + delete qe; + } +} + +/* enqueue to-be-transmitted data */ +int E1_Timeslot::enqueue_tx(const uint8_t *data, unsigned int len) +{ + struct QueueEntry *qe = new QueueEntry(data, len); + if (!qe) + return 0; + m_tx_queue.push(qe); + + return 1; +} + +/* dequeue + write next-to-be-transmitted data from queue */ +int E1_Timeslot::dequeue_tx(void) +{ + struct QueueEntry *qe; + int rc; + + if (m_tx_queue.empty()) { + /* queue is empty; unsubscribe write-events */ + return 0; + } + + qe = m_tx_queue.front(); + m_tx_queue.pop(); + rc = write(m_fd, qe->data, qe->len); + if (rc < 0) { + TTCN_error("error during write: %s\n", strerror(errno)); + /* FIXME: close/delete fd */ + } + else if (rc < qe->len) + TTCN_error("could only write %u of %u bytes\n", rc, qe->len); + + delete qe; + + return 1; +} + + + +E1TS__PT_PROVIDER::E1TS__PT_PROVIDER(const char *par_port_name) + : PORT(par_port_name) +{ + osmo_init_logging2(NULL, NULL); +} + +E1TS__PT_PROVIDER::~E1TS__PT_PROVIDER() +{ +} + +void E1TS__PT_PROVIDER::log(const char *fmt, ...) +{ + TTCN_Logger::begin_event(TTCN_WARNING); + TTCN_Logger::log_event("E1TS Test port (%s): ", get_name()); + va_list args; + va_start(args, fmt); + TTCN_Logger::log_event_va_list(fmt, args); + va_end(args); + TTCN_Logger::end_event(); +} + +void E1TS__PT_PROVIDER::set_parameter(const char *parameter_name, const char *parameter_value) +{ + if (!strcmp(parameter_name, "e1d_socket_path")) + m_e1d_socket_path = parameter_value; + else + TTCN_error("Unsupported E1TS test port parameter `%s'.", parameter_name); +} + +void E1TS__PT_PROVIDER::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, + boolean is_error) +{ + uint8_t buf[65535]; + E1_Timeslot *ts; + int rc; + + /* find E1TS_identity by fd */ + ts = ts_by_fd(fd); + + if (!ts) + TTCN_error("Unknown file descriptor %d\n", fd); + + if (is_readable) { + rc = read(fd, buf, sizeof(buf)); + if (rc > 0) + incoming_message(E1TS__unitdata(ts->m_id, OCTETSTRING(rc, buf))); + else if (rc == 0) { + TTCN_error("EOF on E1TS fd, closing"); + m_ts_by_id.erase(m_ts_by_id.find(ts->m_id)); + m_ts_by_fd.erase(m_ts_by_fd.find(ts->m_fd)); + Handler_Remove_Fd(ts->m_fd); + delete ts; + } + } + + if (is_writable) { + /* dequeue next message; unregister for 'write' if nothing to write */ + if (ts->dequeue_tx() == 0) + Handler_Remove_Fd_Write(ts->m_fd); + } +} + +void E1TS__PT_PROVIDER::user_map(const char * /*system_port*/) +{ + m_e1d_clnt = osmo_e1dp_client_create(NULL, m_e1d_socket_path); +} + +void E1TS__PT_PROVIDER::user_unmap(const char * /*system_port*/) +{ + /* close/destroy all timeslots */ + for (auto it = m_ts_by_id.begin(); it != m_ts_by_id.end(); it++) { + E1_Timeslot *ts = it->second; + Handler_Remove_Fd(ts->m_fd); + delete ts; + } + m_ts_by_id.clear(); + m_ts_by_fd.clear(); + + /* close client connection to daemon */ + osmo_e1dp_client_destroy(m_e1d_clnt); +} + +void E1TS__PT_PROVIDER::user_start() +{ +} + +void E1TS__PT_PROVIDER::user_stop() +{ +} + +static enum osmo_e1dp_ts_mode e1dp_mode(E1TS__mode in) +{ + switch (in) { + case E1TS__PortTypes::E1TS__mode::E1TS__MODE__RAW: + return E1DP_TSMODE_RAW; + case E1TS__PortTypes::E1TS__mode::E1TS__MODE__HDLCFCS: + return E1DP_TSMODE_HDLCFCS; + default: + TTCN_error("Unknown E1TS_mode %d\n", in); + } +} + +E1_Timeslot *E1TS__PT_PROVIDER::ts_by_fd(int fd) +{ + auto it = m_ts_by_fd.find(fd); + if (it == m_ts_by_fd.end()) { + TTCN_error("couldn't find FD for identity"); + return NULL; + } else + return it->second; +} + + +E1_Timeslot *E1TS__PT_PROVIDER::ts_by_id(const E1TS__identity& id) +{ + auto it = m_ts_by_id.find(id); + if (it == m_ts_by_id.end()) + return NULL; + else + return it->second; +} + + +void E1TS__PT_PROVIDER::outgoing_send(const E1TS__open& send_par) +{ + int fd; + enum osmo_e1dp_ts_mode mode = e1dp_mode(send_par.mode()); + + fd = osmo_e1dp_client_ts_open(m_e1d_clnt, send_par.id().interface__nr(), + send_par.id().line__nr(), send_par.id().ts__nr(), mode); + + if (fd >= 0) { + E1_Timeslot *ts = new E1_Timeslot(*this, send_par.id(), send_par.mode(), fd); + m_ts_by_id.insert(std::make_pair(send_par.id(), ts)); + m_ts_by_fd.insert(std::make_pair(fd, ts)); + Handler_Add_Fd_Read(fd); + incoming_message(E1TS__result(send_par.req__hdl(), 0)); + } else { + incoming_message(E1TS__result(send_par.req__hdl(), fd)); + } +} + +void E1TS__PT_PROVIDER::outgoing_send(const E1TS__close& send_par) +{ + /* find fd by map */ + E1_Timeslot *ts = ts_by_id(send_par.id()); + + if (!ts) + return; + + m_ts_by_id.erase(m_ts_by_id.find(send_par.id())); + m_ts_by_fd.erase(m_ts_by_fd.find(ts->m_fd)); + Handler_Remove_Fd(ts->m_fd); + delete ts; +} + +void E1TS__PT_PROVIDER::outgoing_send(const E1TS__unitdata& send_par) +{ + /* find fd by map */ + E1_Timeslot *ts = ts_by_id(send_par.id()); + + if (!ts) + return; + + ts->enqueue_tx(send_par.data(), send_par.data().lengthof()); + Handler_Add_Fd_Write(ts->m_fd); +} + + +} /* namespace */ diff --git a/src/E1TS_PT.hh b/src/E1TS_PT.hh new file mode 100644 index 0000000..9b7c75f --- /dev/null +++ b/src/E1TS_PT.hh @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +#include + +extern "C" { +#include +} + +#include "E1TS_PortTypes.hh" + +namespace E1TS__PortType { + +using namespace E1TS__PortTypes; + +class E1TS__PT_PROVIDER; + +class DerivedId { +public: + DerivedId(const E1TS__identity &id); + unsigned int interface_nr; + unsigned int line_nr; + unsigned int ts_nr; +}; + +class QueueEntry { +public: + QueueEntry(const uint8_t *pdata, unsigned int plen); + ~QueueEntry(); + + uint8_t *data; + unsigned int len; +}; + +class E1_Timeslot { +public: + E1_Timeslot(E1TS__PT_PROVIDER &pr, E1TS__identity id, E1TS__mode mode, int fd); + ~E1_Timeslot(); + + int enqueue_tx(const uint8_t *data, unsigned int len); + int dequeue_tx(void); + + E1TS__identity m_id; + int m_fd; + +private: + E1TS__PT_PROVIDER &m_pt; + E1TS__mode m_mode; + std::queue m_tx_queue; +}; + + +class E1TS__PT_PROVIDER : public PORT { +public: + E1TS__PT_PROVIDER(const char *par_port_name); + ~E1TS__PT_PROVIDER(); + + void set_parameter(const char *parameter_name, const char *parameter_value); + +private: + void Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error); + +protected: + void user_map(const char *system_port); + void user_unmap(const char *system_port); + + void user_start(); + void user_stop(); + + void outgoing_send(const E1TS__open& send_par); + void outgoing_send(const E1TS__close& send_par); + void outgoing_send(const E1TS__unitdata& send_par); + + virtual void incoming_message(const E1TS__result& incoming_par) = 0; + virtual void incoming_message(const E1TS__unitdata &incoming_par) = 0; + +public: + void log(const char *fmt, ...); + +private: + /* parameter */ + const char *m_e1d_socket_path = E1DP_DEFAULT_SOCKET; + + E1_Timeslot *ts_by_fd(int fd); + E1_Timeslot *ts_by_id(const E1TS__identity &id); + + /* client to the E1 Daemon */ + struct osmo_e1dp_client *m_e1d_clnt; + + /* per-timeslot file descriptors */ + std::map m_ts_by_id; + std::map m_ts_by_fd; + +}; + + + +} diff --git a/src/E1TS_PortType.ttcn b/src/E1TS_PortType.ttcn new file mode 100644 index 0000000..fdaa6f3 --- /dev/null +++ b/src/E1TS_PortType.ttcn @@ -0,0 +1,12 @@ +module E1TS_PortType { +import from E1TS_PortTypes all; + +type port E1TS_PT message { + out E1TS_open; + in E1TS_result; + + out E1TS_unitdata; + in E1TS_unitdata; +} with { extension "provider" }; + +} diff --git a/src/E1TS_PortTypes.ttcn b/src/E1TS_PortTypes.ttcn new file mode 100644 index 0000000..bccb996 --- /dev/null +++ b/src/E1TS_PortTypes.ttcn @@ -0,0 +1,87 @@ +module E1TS_PortTypes { + +type record E1TS_identity { + integer interface_nr, + integer line_nr, + integer ts_nr +}; + +type enumerated E1TS_mode { + E1TS_MODE_RAW, + E1TS_MODE_HDLCFCS +}; + +type record E1TS_open { + integer req_hdl, + E1TS_identity id, + E1TS_mode mode, + charstring driver +}; + +type record E1TS_close { + E1TS_identity id +}; + +type record E1TS_result { + integer req_hdl, + integer status +}; + +type record E1TS_unitdata { + E1TS_identity id, + octetstring data +}; + +template (value) E1TS_identity ts_E1TS_ID(template (value) integer if_nr, + template (value) integer li_nr, + template (value) integer ts_nr) := { + interface_nr := if_nr, + line_nr := li_nr, + ts_nr := ts_nr +} + +template (present) E1TS_identity tr_E1TS_ID(template (present) integer if_nr, + template (present) integer li_nr, + template (present) integer ts_nr) := { + interface_nr := if_nr, + line_nr := li_nr, + ts_nr := ts_nr +} + +template (value) E1TS_open ts_E1TS_open(template (value) integer req_hdl, + template (value) E1TS_identity id, + template (value) E1TS_mode mode := E1TS_MODE_RAW, + template (value) charstring driver := "e1d") := { + req_hdl := req_hdl, + id := id, + mode := mode, + driver := driver +} + + +template (value) E1TS_close ts_E1TS_close(template (value) E1TS_identity id) := { + id := id +} + +template (present) E1TS_result tr_E1TS_result(template (present) integer req_hdl := ?, + template (present) integer status := ?) := { + req_hdl := req_hdl, + status := status +} + +template (value) E1TS_unitdata ts_E1TS_unitdata(template (value) E1TS_identity id, + template (value) octetstring data) := { + id := id, + data := data +} + +template (present) E1TS_unitdata tr_E1TS_unitdata(template (present) E1TS_identity id, + template (present) octetstring data) := { + id := id, + data := data +} + + + + +}