Compare commits

..

2 Commits

Author SHA1 Message Date
Pau Espin Pedrol
1d23dfb0aa Bump version: 1.11.0.1-ef3e5 → 1.11.1
Change-Id: I45b2d09948bb6666c52466b59beb301d8da972c1
2023-03-10 14:55:22 +01:00
Pau Espin Pedrol
6087326beb mgcp_network: Unregister osmo_fd before closing fd
(cherry picked from commit 6c303664f5)

Change-Id: Id03011a11be17e9c0a53b01444754dd633232d2e
2023-03-10 14:55:11 +01:00
59 changed files with 1633 additions and 3203 deletions

View File

@@ -24,7 +24,7 @@ pkgconfig_DATA = \
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = \
.version \
README.md \
contrib/osmo-mgw.spec.in \
debian \
git-version-gen \
osmoappdesc.py \

24
README Normal file
View File

@@ -0,0 +1,24 @@
About OsmoMGW
=============
OsmoMGW originated from the OpenBSC project, which started as a minimalistic
all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
approach to fully independent separate programs as in typical GSM networks.
OsmoMGW was one of the parts split off from the old openbsc.git. It originated
as a solution to merely navigate RTP streams through a NAT, but has since
matured to a Media Gateway implementation that is capable of streaming RTP for
2G (AoIP) and 3G (IuCS) GSM networks as well as (still not implemented at time
of writing) transcoding between TRAU, various RTP payloads and IuUP.
The OsmoMGW program exposes an MGCP interface towards clients like OsmoMSC and
OsmoBSC, and receives and sends RTP streams as configured via MGCP.
The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC (found
in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
Find OsmoMGW issue tracker and wiki online at
https://osmocom.org/projects/osmo-mgw
https://osmocom.org/projects/osmo-mgw/wiki

102
README.md
View File

@@ -1,102 +0,0 @@
osmo-mgw - Osmocom MGW (Media GateWay) Implementation
=====================================================
This repository contains a C-language implementation of an MGW (Media
GateWay) for use [not only] within the 2G (GSM) and/or 3G (UMTS)
Cellular Network built using Osmocom CNI (Cellular Network
Infrastructure) software.
The OsmoMGW program provides an MGCP interface towards an MGCP call agent
(client) like OsmoMSC and OsmoBSC, and receives and sends RTP streams as
configured via the MGCP control plane.
This Media Gateway implementation is capable of
* streaming RTP for 2G (3GPP AoIP and Abis-over-IP)
* streaming RTP for 3G (IuCS including the IuFP protocol)
* TDM (E1/T1) based Abis interface with TRAU frames on 16k sub-slots
* basic support for LCLS (Local Call, Local Switch) related features
* various built-in translation capabilities
* between Abis TRAU frames and RTP formats
* between 2G AMR/RTP and 3G AMR/IuFP/RTP
* between bandwidth-efficient and octet-aligned AMR
* between different standards for encapsulating GSM HR codec frames in RTP
osmo-mgw is typically co-located with
* osmo-bsc (GSM BSC)
* osmo-msc (GSM/UMTS MSC)
* osmo-hnbgw (UMTS HNBGW); osmo-mgw implements RTP relay between Iuh
and IuCS interfaces
The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC
(found in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
Homepage
--------
You can find the OsmoMGW issue tracker and wiki online at
<https://osmocom.org/projects/osmo-mgw> and <https://osmocom.org/projects/osmo-mgw/wiki>.
GIT Repository
--------------
You can clone from the official osmo-mgw.git repository using
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw>
Documentation
-------------
User Manuals and VTY reference manuals are [optionally] built in PDF form
as part of the build process.
Pre-rendered PDF version of the current "master" can be found at
[User Manual](https://ftp.osmocom.org/docs/latest/osmomgw-usermanual.pdf)
as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmomgw-vty-reference.pdf)
Mailing List
------------
Discussions related to osmo-mgw are happening on the
openbsc@lists.osmocom.org mailing list, please see
<https://lists.osmocom.org/mailman/listinfo/openbsc> for subscription
options and the list archive.
Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
Contributing
------------
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
We use a gerrit based patch submission/review process for managing
contributions. Please see
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
more details
The current patch queue for osmo-mgw can be seen at
<https://gerrit.osmocom.org/#/q/project:osmo-mgw+status:open>
History
-------
OsmoMGW originated from the OpenBSC project, which started as a minimalistic
all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
approach to fully independent separate programs as in typical GSM networks.
OsmoMGW was one of the parts split off from the old openbsc.git. It originated
as a solution to merely navigate RTP streams through a NAT, but has since
matured.

View File

@@ -1,11 +1,26 @@
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
# LIBVERSION=c:r:a
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
libosmocore bump_dep; workaround Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
# When cleaning up this file upon a release:
#
# - Note that the release version number is entirely unrelated to the API
# versions. A release version 5.2.3 may happily have an API version of 42:7:5.
#
# - Bump API version in src/lib*/Makefile.am files according to chapter
# "Library interface versions" of the libtool documentation.
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
#
# - Iff the 'current' API version has changed, rename debian/lib*.install
#
# API version bumping for the impatient:
# LIBVERSION=c:r:a (current:revision_of_current:backwards_compat_age)
# 5:2:4 means that
# - this implements version 5 of the API;
# - this is the 2nd (compatible) revision of API version 5;
# - this is backwards compatible to all APIs since 4 versions ago,
# i.e. callers that need API versions from 1 to 5 can use this.
#
# Bumping API versions recipe:
# If the library source code has changed at all since the last update, r++;
# If any interfaces have been added, removed, or changed since the last update, c++, r=0;
# If any interfaces have been added since the last public release, a++;
# If any interfaces have been removed or changed since the last public release, a=0.
#
#library what description / commit summary line

View File

@@ -44,16 +44,15 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.4.0)
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
CFLAGS="$CFLAGS -pthread"
LDFLAGS="$LDFLAGS -pthread"
AC_ARG_ENABLE(sanitize,
@@ -204,4 +203,5 @@ AC_OUTPUT(
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-mgw.spec
Makefile)

137
contrib/osmo-mgw.spec.in Normal file
View File

@@ -0,0 +1,137 @@
#
# spec file for package osmo-mgw
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: osmo-mgw
Version: @VERSION@
Release: 0
Summary: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Hardware/Mobile
URL: https://osmocom.org/projects/osmo-mgw
Source: %{name}-%{version}.tar.xz
BuildRequires: automake >= 1.9
BuildRequires: libtool >= 2
BuildRequires: pkgconfig >= 0.20
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libosmo-netif) >= 1.3.0
BuildRequires: pkgconfig(libosmocore) >= 1.8.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0
BuildRequires: pkgconfig(libosmogsm) >= 1.8.0
BuildRequires: pkgconfig(libosmovty) >= 1.8.0
BuildRequires: pkgconfig(libosmocoding) >= 1.8.0
BuildRequires: pkgconfig(libosmoabis) >= 1.4.0
BuildRequires: pkgconfig(libosmotrau) >= 1.4.0
%{?systemd_requires}
%description
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
%package -n libosmo-mgcp-client11
Summary: Osmocom's Media Gateway Control Protocol client library
Group: System/Libraries
%description -n libosmo-mgcp-client11
Osmocom's Media Gateway Control Protocol client library.
%package -n libosmo-mgcp-client-devel
Summary: Development files for Osmocom's Media Gateway Control Protocol client library
Group: Development/Libraries/C and C++
Requires: libosmo-mgcp-client11 = %{version}
%description -n libosmo-mgcp-client-devel
Osmocom's Media Gateway Control Protocol client librarary.
This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-mgcp-client.
%package -n libosmo-mgcp-devel
Summary: Development files for Osmocom's Media Gateway server library
Group: Development/Libraries/C and C++
%description -n libosmo-mgcp-devel
Osmocom's Media Gateway Control Protocol server library.
This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-mgcp.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
--disable-static \
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
find %{buildroot} -type f -name "*.la" -delete -print
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%post -n libosmo-mgcp-client11 -p /sbin/ldconfig
%postun -n libosmo-mgcp-client11 -p /sbin/ldconfig
%if 0%{?suse_version}
%preun
%service_del_preun osmo-mgw.service
%postun
%service_del_postun osmo-mgw.service
%pre
%service_add_pre osmo-mgw.service
%post
%service_add_post osmo-mgw.service
%endif
%files
%license COPYING
%doc AUTHORS README
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-mgw
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
%{_bindir}/osmo-mgw
%{_unitdir}/osmo-mgw.service
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
%files -n libosmo-mgcp-client11
%{_libdir}/libosmo-mgcp-client.so.11*
%files -n libosmo-mgcp-client-devel
%{_libdir}/libosmo-mgcp-client.so
%{_libdir}/pkgconfig/libosmo-mgcp-client.pc
%dir %{_includedir}/osmocom
%dir %{_includedir}/osmocom/mgcp_client
%{_includedir}/osmocom/mgcp_client/*.h
%files -n libosmo-mgcp-devel
%dir %{_includedir}/osmocom
%dir %{_includedir}/osmocom/mgcp
%{_includedir}/osmocom/mgcp/*.h
%changelog

View File

@@ -1,19 +1,13 @@
[Unit]
Description=Osmocom Media Gateway (MGW)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
LimitNOFILE=65536
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Restart=always
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

169
debian/changelog vendored
View File

@@ -1,173 +1,8 @@
osmo-mgw (1.13.1) unstable; urgency=medium
osmo-mgw (1.11.1) unstable; urgency=medium
[ Philipp Maier ]
* mgcp_network: use an uint16_t to store the port number
* mgcp_network: add missing ntohs
[ Pau Espin Pedrol ]
* tests/mgcp/mgcp_test: Add some extra asserts in code
-- Oliver Smith <osmith@sysmocom.de> Thu, 12 Sep 2024 13:53:19 +0200
osmo-mgw (1.13.0) unstable; urgency=medium
[ Neels Hofmeyr ]
* add mgcp_conn_rtp_type_names[]
* mgcp_parse_audio_port_pt(): fix buffer overflow
* client: replace two assertions with graceful error handling
* systemd,manual: set LimitNOFILE=65536
* IuUP: allow Initialization from any address if not yet set
* check_rtp_origin: drop special case for legacy IuUP hack
* mgcp_client_test: fix function name
* fix possible NULL deref on early media
* client: move some items to internal header
* client: safely handle dealloc on event dispatch
* build: move mgcp/*.h to noinst_HEADERS, drop RPM libosmo-mgcp-devel
* client: deprecate legacy API
* client: collapse codecs[] and ptmap[]; allow codec variants
* client: allow MGCP_MAX_CODECS entries
* client SDP: more verbose error logging
* mgcp_client_test: add test_parse_response()
* drop (now) unused code
* tests/mgcp: add update_exp target
* drop get_net_downlink_format_cb
* drop cfg 'sdp audio fmtp-extra'
* mgcp_codec_decide: remove redundant lookup
* tweak DEBUG log
* mgcp_test: fix false negatives in test output
* mgw: do not fail MGCP on codec mismatch
* mgcp-client: always send 'm=audio' line
* mgcp_test.c: verify osmo-mgw accepts m=audio 0
* mgcp_test.c: fix various missing '\r' and '\n'
* mgcp_test: test a=ptime:20, not 40
* mgcp_test: add CRCX for IUFP in sendrecv
* do not FAIL on CRCX in sendrecv mode
[ Keith Whyte ]
* vty and log: also show local port for RTP conns
[ Andreas Eversberg ]
* Use uniform log format for default config files
[ Pau Espin Pedrol ]
* mgcp_network: Improve err logging when rtp pkt from unexpected origin comes in
* cosmetic: Fix line indentation
* IuUP: Allow Initialization with set rem IP address and unset rem port
* mgcp-client: Transmit remote IP addr in CRCX if known and port=0
* Fix IuUP RTP hdr seqnr field not incremented
* iuup: Increment RTP hdr seqnr even if Tx over UDP fails
[ Vadim Yanitskiy ]
* mgcp: simplify getting msgb tail in mgcp_msg_terminate_nul()
* mgcp: reserve once byte for '\0' in mgcp_do_read()
* mgcp: correctly put NUL character in mgcp_msg_terminate_nul()
* build: include README into the release tarball
[ neels ]
* Revert "drop (now) unused code"
[ Harald Welte ]
* Convert README to README.md and expand like in other projects
* migrate mgcp_client from osmo_wqueue to osmo_io
* mgw: Add our usual SIGABRT, SIGUSR1 signal handlers
* don't log useless "transcoding disabled" message
* remove strange loop for non-existant transcoding support
* simplify unused transcoding/processing call-back
* remove osmo_fd from mgcp_create_bind()
* Change msgb ownership in processing of received msgb
* cosmetic: make linter happy
* Convert RTP/RTCP/OSMUX I/O from osmo_fd to osmo_io
[ Oliver Smith ]
* contrib: remove rpm spec file
* contrib/systemd: run as osmocom user
* doc: example configs: fix deprecation warnings
[ Mychaela N. Falconia ]
* E1: support HRv1 codec on both 16k and 8k subslots
* fix E1 TS output when used with osmo-e1d
-- Oliver Smith <osmith@sysmocom.de> Wed, 24 Jul 2024 15:44:47 +0200
osmo-mgw (1.12.1) unstable; urgency=medium
[ Pau Espin Pedrol ]
* mgcp-client: Fix missing include in mgcp_client_pool.h
* mgcp-client: Introduce API osmo_mgcpc_ep_local_name()
* mgw: Configure IuUP if codec set during MDCX
-- Oliver Smith <osmith@sysmocom.de> Thu, 28 Sep 2023 15:58:17 +0200
osmo-mgw (1.12.0) unstable; urgency=medium
[ Philipp Maier ]
* mgcp_sdp: add spec reference
* mgcp_sdp: cosmetic: remove newline
* mgcp_endp: cosmetic move mgcp_endp_release to the end
* mgcp_endp: cosmetic: remove unnecessary new line
* mgcp_e1: fix log output
* mgcp_e1: be more frugal withe E1 line resources
* mgcp_client: fix sourcecode formatting
* mgcp_e1: fix typo
* mgcp_e1: rewrite comment
* mgcp_e1: rename e1_send to e1_send_ts_frame
* mgcp_e1: cosmetic: rewrite comment
* Revert "mgcp_codec: do not differentiate between oa and bwe when comparing codec"
* mgcp_codec: fix oa/bwe comparison in mgcp_codec_pt_translate()
* mgcp_codec: refactor payload type converstion
* mgcp_codec: cosmetic: remove line break in api-doc
* mgcp_network: fix apidoc
* mgcp_vty: add warnings for deprecated config options
* mgcp_codec: move mgcp_codec_decide down
* mgcp_codec: fix codec decision
* mgcp_network: do not deliver RTP packets with unpatched PT
* mgcp_codec: be sensitive about IuFP when checking codecs
* mgcp_client.h: also add spec ref to the other 3gpp defined payload types
[ Harald Welte ]
* cosmetic: Fix grammar suggesting reading _the_ user manual
[ arehbein ]
* Transition to use of 'telnet_init_default'
[ Oliver Smith ]
* mgcp_client: mgcp_msg_gen: add more error logs
* mgcp_client_pool: add mgcp_client_pool_empty()
* Cosmetic: mgcp_client: fix typo
* debian: set compat level to 10
* systemd: depend on networking-online.target
* Cosmetic: fix a typo
* mgcp_client: check rc of map_str_to_codec
[ Pau Espin Pedrol ]
* mgcp_network: Unregister osmo_fd before closing fd
* mgcp-client: Call osmo_fd_unregister() before closing and changing bfd->fd
* mgcp-client: Drop unused struct mgcp_client field
* mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
* mgcp-client: Move some static functions further above
* mgw: Allow auditing speciall 'null' endpoint
* mgcp-client: Add keepalive feature
* mgcp_client: pool: Only pick clients with an MGCP link considered to be UP
* mgcp-client: Always mark client as UP if keepalive request-interval disabled
* mgcp-client: Mark client as UP when keepalive request-interval/timeout is disabled through VTY
[ Vadim Yanitskiy ]
* */Makefile.am: libraries shall not be in AM_LDFLAGS
* tests: use -no-install libtool flag to avoid ./lt-* scripts
* tests: $(BUILT_SOURCES) is not defined, depend on osmo-mgw
* copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
[ Neels Hofmeyr ]
* mgcp_find_section_end(): skip spaces at start of SDP
* mgcp_client: simpler error handling
* mgcp: fix "L: a:" header parsing: heed ";" separator
* mgcp_client: tweak extract_codec_name() implementation
[ Andreas Eversberg ]
* ASCI: Add new mode for voice group/broadcast call
* ASCI: Support conference briding with 1..n connections
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:48:51 +0200
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 10 Mar 2023 14:55:21 +0100
osmo-mgw (1.11.0) unstable; urgency=medium

2
debian/compat vendored
View File

@@ -1 +1 @@
10
9

14
debian/control vendored
View File

@@ -2,14 +2,14 @@ Source: osmo-mgw
Section: net
Priority: extra
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>= 10),
Build-Depends: debhelper (>=9),
dh-autoreconf,
pkg-config,
autotools-dev,
libosmocore-dev (>= 1.10.0),
libosmo-netif-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.6.0),
osmo-gsm-manuals-dev (>= 1.6.0)
libosmocore-dev (>= 1.8.0),
libosmo-netif-dev (>= 1.3.0),
libosmo-abis-dev (>= 1.4.0),
osmo-gsm-manuals-dev (>= 1.4.0)
Standards-Version: 3.9.8
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
@@ -21,7 +21,7 @@ Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-mgcp-client14
Package: libosmo-mgcp-client11
Section: libs
Architecture: any
Multi-Arch: same
@@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp-client14 (= ${binary:Version}), ${misc:Depends}
Depends: libosmo-mgcp-client11 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: osmo-mgw-doc

4
debian/copyright vendored
View File

@@ -6,7 +6,7 @@ Files: *
Copyright: 2009-2014 On-Waves
2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
2016-2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
2016-2017 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
License: AGPL-3.0+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
@@ -22,7 +22,7 @@ License: AGPL-3.0+
along with this program. If not, see <http://www.gnu.org/licenses/>.
Files: src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
Copyright: 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
Copyright: 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
2009 by Harald Welte <laforge@gnumonks.org>
2009-2011 by Holger Hans Peter Freyther

38
debian/postinst vendored
View File

@@ -1,38 +0,0 @@
#!/bin/sh -e
case "$1" in
configure)
# Create the osmocom group and user (if it doesn't exist yet)
if ! getent group osmocom >/dev/null; then
groupadd --system osmocom
fi
if ! getent passwd osmocom >/dev/null; then
useradd \
--system \
--gid osmocom \
--home-dir /var/lib/osmocom \
--shell /sbin/nologin \
--comment "Open Source Mobile Communications" \
osmocom
fi
# Fix permissions of previous (root-owned) install (OS#4107)
if dpkg --compare-versions "$2" le "1.13.0"; then
if [ -e /etc/osmocom/osmo-mgw.cfg ]; then
chown -v osmocom:osmocom /etc/osmocom/osmo-mgw.cfg
chmod -v 0660 /etc/osmocom/osmo-mgw.cfg
fi
if [ -d /etc/osmocom ]; then
chown -v root:osmocom /etc/osmocom
chmod -v 2775 /etc/osmocom
fi
mkdir -p /var/lib/osmocom
chown -R -v osmocom:osmocom /var/lib/osmocom
fi
;;
esac
# dh_installdeb(1) will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#

View File

@@ -1,25 +1,20 @@
!
! MGCP configuration example
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
e1_input
e1_line 0 driver dahdi
e1_line 0 port 0
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16001
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 512
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc

View File

@@ -1,22 +1,17 @@
!
! MGCP configuration example
!
log stderr
logging color 1
logging print category-hex 0
logging print category 1
logging timestamp 0
logging print file basename last
logging print level 1
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16001
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 512
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc

View File

@@ -91,10 +91,4 @@ encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
not yet useable.
NOTE: the VTY command "show mgcp" can be used to get a list of all available
endpoints (including identifiers)
=== The `null` endpoint
OsmoMGW offers a special `null@<domain>` endpoint which can be audited at all times.
This is useful for MGCP clients who wish to submit requests to OsmoMGW
periodically to find out whether it is still reachable and in a working state.
endpoints (including identifiers)

View File

@@ -23,20 +23,3 @@ arguments:
Disable colors for logging to stderr. This has mostly been
deprecated by VTY based logging configuration, see <<logging>>
for more information.
=== Configure limits
When servicing hundreds of media endpoints, it may be necessary to adjust the
operating system's limit on open file descriptors for the osmo-mgw process. A
typical default limit imposed by operating systems is 1024; this would be
exceeded by, for example, about 256 active voice calls with 4 RTP/RTPC ports
each, sockets for other interfaces not considered yet.
It should be ok to set an OS limit on open file descriptors as high as 65536
for osmo-mgw, which practically rules out failure from running out of file
descriptors anywhere (<16,000 active calls).
When using systemd, the file descriptor limit may be adjusted in the service
file by the `LimitNOFILE` setting ("Number of Open FILE descriptors"). OsmoMGW
ships a systemd service file with a high LimitNOFILE setting.

View File

@@ -3,14 +3,10 @@ SUBDIRS = \
$(NULL)
nobase_include_HEADERS = \
osmocom/mgcp_client/defs.h \
osmocom/mgcp_client/mgcp_client.h \
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
osmocom/mgcp_client/mgcp_client_fsm.h \
osmocom/mgcp_client/mgcp_client_pool.h \
$(NULL)
noinst_HEADERS = \
osmocom/mgcp/mgcp.h \
osmocom/mgcp/mgcp_common.h \
osmocom/mgcp/osmux.h \

View File

@@ -24,7 +24,6 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/logging.h>
@@ -71,10 +70,12 @@ typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
/**
* Return:
* < 0 in case no audio was processed
* >= 0 in case audio was processed.
* >= 0 in case audio was processed. The remaining payload
* length will be returned.
*/
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end, struct msgb *msg);
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
struct mgcp_conn_rtp;
@@ -137,6 +138,8 @@ struct mgcp_config {
mgcp_processing rtp_processing_cb;
mgcp_processing_setup setup_rtp_processing_cb;
mgcp_get_format get_net_downlink_format_cb;
struct osmo_wqueue gw_fd;
struct mgcp_port_range net_ports;
@@ -205,5 +208,6 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
int mgcp_send_reset_all(struct mgcp_config *cfg);
int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio);
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len);
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio);
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);

View File

@@ -13,9 +13,9 @@ struct mgcp_conn_rtp;
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr);
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type);

View File

@@ -47,7 +47,6 @@ enum mgcp_connection_mode {
MGCP_CONN_SEND_ONLY = 2,
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
MGCP_CONN_CONFECHO = 8 | MGCP_CONN_RECV_SEND,
};
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
@@ -68,11 +67,11 @@ struct mgcp_codec_param {
/* Ensure that the msg->l2h is NUL terminated. */
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
{
unsigned char *tail = msg->tail; /* char after l2 data */
unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
if (tail[-1] == '\0')
/* nothing to do */;
else if (msgb_tailroom(msg) > 0)
msgb_put_u8(msg, (uint8_t)'\0');
tail[0] = '\0';
else if (tail[-1] == '\r' || tail[-1] == '\n')
tail[-1] = '\0';
else {

View File

@@ -49,11 +49,6 @@ enum mgcp_conn_rtp_type {
MGCP_RTP_OSMUX,
MGCP_RTP_IUUP,
};
extern const struct value_string mgcp_conn_rtp_type_names[];
static inline const char *mgcp_conn_rtp_type_name(enum mgcp_conn_rtp_type val)
{
return get_value_string(mgcp_conn_rtp_type_names, val);
}
/*! Connection type, specifies which member of the union "u" in mgcp_conn
* contains a useful connection description (currently only RTP) */

View File

@@ -23,5 +23,5 @@ static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6,
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts);
void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);

View File

@@ -130,10 +130,10 @@ struct mgcp_endpoint {
};
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
void mgcp_endp_release(struct mgcp_endpoint *endp);
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
void mgcp_endp_update(struct mgcp_endpoint *endp);
bool mgcp_endp_is_wildcarded(const char *epname);
bool mgcp_endp_is_null(const char *epname);
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
@@ -145,4 +145,3 @@ void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
const struct mgcp_trunk *trunk);
void mgcp_endp_release(struct mgcp_endpoint *endp);

View File

@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/mgcp/mgcp.h>
@@ -94,7 +93,7 @@ struct mgcp_rtp_end {
struct osmo_sockaddr addr;
/* in network byte order */
uint16_t rtcp_port;
int rtcp_port;
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
@@ -109,6 +108,7 @@ struct mgcp_rtp_end {
int frames_per_packet;
uint32_t packet_duration_ms;
int maximum_packet_time; /* -1: not set */
char *fmtp_extra;
/* are we transmitting packets (true) or dropping (false) outbound packets */
bool output_enabled;
/* FIXME: This parameter can be set + printed, but is nowhere used! */
@@ -121,8 +121,8 @@ struct mgcp_rtp_end {
bool rfc5993_hr_convert;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_io_fd *rtp;
struct osmo_io_fd *rtcp;
struct osmo_fd rtp;
struct osmo_fd rtcp;
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
@@ -160,7 +160,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn_dst,
@@ -180,7 +181,7 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
int id, int inc);
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id);
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
uint32_t mgcp_get_current_ts(unsigned codec_rate);
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);

View File

@@ -27,9 +27,12 @@ struct mgcp_trunk {
unsigned int trunk_nr;
enum mgcp_trunk_type trunk_type;
char *audio_fmtp_extra;
int audio_send_ptime;
int audio_send_name;
int no_audio_transcoding;
int omit_rtcp;
int keepalive_interval;
@@ -63,7 +66,7 @@ struct mgcp_trunk {
/* E1 specific */
struct {
unsigned int vty_line_nr;
uint8_t ts_usecount[NUM_E1_TS-1];
bool ts_in_use[NUM_E1_TS-1];
struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
/* Note: on an E1 line TS 0 is devoted to framing and
* alignment and therefore only NUM_E1_TS-1 timeslots

View File

@@ -1,7 +0,0 @@
#include <osmocom/core/defs.h>
#if BUILDING_LIBOSMOMGCPCLIENT
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text)
#else
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text) OSMO_DEPRECATED(text)
#endif

View File

@@ -3,7 +3,6 @@
#include <stdint.h>
#include <arpa/inet.h>
#include <osmocom/mgcp_client/defs.h>
#include <osmocom/mgcp_client/mgcp_common.h>
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
@@ -11,7 +10,7 @@
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
#define MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP "null"
#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
struct msgb;
@@ -36,12 +35,6 @@ struct mgcp_client_conf {
/* human readable name / description */
char *description;
struct {
uint32_t timeout_sec;
uint32_t req_interval_sec;
char req_endpoint_name[MGCP_ENDPOINT_MAXLEN];
} keepalive;
};
typedef unsigned int mgcp_trans_id_t;
@@ -52,12 +45,12 @@ enum mgcp_codecs {
CODEC_GSM_8000_1 = 3,
CODEC_PCMA_8000_1 = 8,
CODEC_G729_8000_1 = 18,
CODEC_GSMEFR_8000_1 = 110, /* 3GPP TS 48.103 table 5.4.2.2.1 */
CODEC_GSMHR_8000_1 = 111, /* 3GPP TS 48.103 table 5.4.2.2.1 */
CODEC_AMR_8000_1 = 112, /* 3GPP TS 48.103 table 5.4.2.2.1 */
CODEC_AMRWB_16000_1 = 113, /* 3GPP TS 48.103 table 5.4.2.2.1 */
CODEC_GSMEFR_8000_1 = 110,
CODEC_GSMHR_8000_1 = 111,
CODEC_AMR_8000_1 = 112,
CODEC_AMRWB_16000_1 = 113,
CODEC_IUFP = 96,
CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
};
/* Note: when new codec types are added, the corresponding value strings
* in mgcp_client.c (codec_table) must be updated as well. Enumerations
@@ -79,7 +72,27 @@ struct ptmap {
unsigned int pt;
};
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
struct mgcp_response_head {
int response_code;
mgcp_trans_id_t trans_id;
char comment[MGCP_COMMENT_MAXLEN];
char conn_id[MGCP_CONN_ID_MAXLEN];
char endpoint[MGCP_ENDPOINT_MAXLEN];
bool x_osmo_osmux_use;
uint8_t x_osmo_osmux_cid;
};
struct mgcp_response {
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
char audio_ip[INET6_ADDRSTRLEN];
unsigned int ptime;
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
unsigned int codecs_len;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
};
enum mgcp_verb {
MGCP_VERB_CRCX,
@@ -89,8 +102,38 @@ enum mgcp_verb {
MGCP_VERB_RSIP,
};
struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
void mgcp_client_conf_init(struct mgcp_client_conf *conf) OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use mgcp_client_conf_alloc() (or even better, switch to the mgcp_client_pool API!)");
#define MGCP_MSG_PRESENCE_ENDPOINT 0x0001
#define MGCP_MSG_PRESENCE_CALL_ID 0x0002
#define MGCP_MSG_PRESENCE_CONN_ID 0x0004
#define MGCP_MSG_PRESENCE_AUDIO_IP 0x0008
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
#define MGCP_MSG_PRESENCE_X_OSMO_IGN 0x8000
struct mgcp_msg {
enum mgcp_verb verb;
/* See MGCP_MSG_PRESENCE_* constants */
uint32_t presence;
char endpoint[MGCP_ENDPOINT_MAXLEN];
unsigned int call_id;
char *conn_id;
uint16_t audio_port;
char *audio_ip;
enum mgcp_connection_mode conn_mode;
unsigned int ptime;
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
unsigned int codecs_len;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
uint32_t x_osmo_ign;
bool x_osmo_osmux_use;
int x_osmo_osmux_cid; /* -1 is wildcard */
bool param_present;
struct mgcp_codec_param param;
};
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
int mgcp_client_config_write(struct vty *vty, const char *indent);
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
@@ -110,8 +153,20 @@ const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
uint8_t rate, uint8_t offset);
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
int mgcp_response_parse_params(struct mgcp_response *r);
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
enum mgcp_connection_mode;
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
extern const struct value_string mgcp_client_connection_mode_strs[];
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
{

View File

@@ -45,7 +45,6 @@ static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep);
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);

View File

@@ -29,11 +29,11 @@ struct mgcp_conn_peer {
/*! RTP packetization interval (optional) */
unsigned int ptime;
/*! Deprecated. Use only ptmap[].codec in new code. */
enum mgcp_codecs codecs[MGCP_MAX_CODECS]
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
unsigned int codecs_len
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
/*! RTP codec list (optional) */
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
/*! Number of codecs in RTP codec list (optional) */
unsigned int codecs_len;
/*! RTP payload type map (optional, only needed when payload types are
* used that differ from what IANA/3GPP defines) */
@@ -64,15 +64,11 @@ struct mgcp_conn_peer {
};
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_alloc() and osmo_mgcpc_ep_ci_add() instead");
int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_request() instead");
void mgcp_conn_delete(struct osmo_fsm_inst *fi)
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_dlcx() instead");
uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci.mgcp_ci_str instead");
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);

View File

@@ -1,7 +1,6 @@
#pragma once
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/write_queue.h>
#define MSGB_CB_MGCP_TRANS_ID 0
@@ -13,39 +12,18 @@ struct reset_ep {
struct mgcp_client {
struct mgcp_client_conf actual;
struct osmo_io_fd *iofd;
struct osmo_wqueue wq;
mgcp_trans_id_t next_trans_id;
struct llist_head responses_pending;
struct llist_head inuse_endpoints;
struct mgcp_client_pool_member *pool_member;
struct osmo_timer_list keepalive_tx_timer;
struct osmo_timer_list keepalive_rx_timer;
bool conn_up;
};
struct mgcp_response_head {
int response_code;
mgcp_trans_id_t trans_id;
char comment[MGCP_COMMENT_MAXLEN];
char conn_id[MGCP_CONN_ID_MAXLEN];
char endpoint[MGCP_ENDPOINT_MAXLEN];
bool x_osmo_osmux_use;
uint8_t x_osmo_osmux_cid;
struct mgcp_inuse_endpoint {
struct llist_head entry;
uint16_t id;
};
struct mgcp_response {
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
char audio_ip[INET6_ADDRSTRLEN];
unsigned int ptime;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
};
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (*mgcp_response_cb_t)(struct mgcp_response *response, void *priv);
struct mgcp_response_pending {
struct llist_head entry;
@@ -61,41 +39,3 @@ struct mgcp_response_pending * mgcp_client_pending_add(
mgcp_trans_id_t trans_id,
mgcp_response_cb_t response_cb,
void *priv);
#define MGCP_MSG_PRESENCE_ENDPOINT 0x0001
#define MGCP_MSG_PRESENCE_CALL_ID 0x0002
#define MGCP_MSG_PRESENCE_CONN_ID 0x0004
#define MGCP_MSG_PRESENCE_AUDIO_IP 0x0008
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
#define MGCP_MSG_PRESENCE_X_OSMO_IGN 0x8000
struct mgcp_msg {
enum mgcp_verb verb;
/* See MGCP_MSG_PRESENCE_* constants */
uint32_t presence;
char endpoint[MGCP_ENDPOINT_MAXLEN];
unsigned int call_id;
char *conn_id;
uint16_t audio_port;
char *audio_ip;
enum mgcp_connection_mode conn_mode;
unsigned int ptime;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
uint32_t x_osmo_ign;
bool x_osmo_osmux_use;
int x_osmo_osmux_cid; /* -1 is wildcard */
bool param_present;
struct mgcp_codec_param param;
};
int mgcp_response_parse_params(struct mgcp_response *r);
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);

View File

@@ -2,8 +2,6 @@
#include <stdbool.h>
#include <osmocom/vty/vty.h>
struct mgcp_client;
struct mgcp_client_pool;
struct mgcp_client_pool_member;
@@ -14,7 +12,6 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool);
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);

View File

@@ -13,6 +13,12 @@ AM_CFLAGS = \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)
# Libraries
SUBDIRS = \
libosmo-mgcp-client \

View File

@@ -14,12 +14,14 @@ AM_CFLAGS = \
$(NULL)
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)
# This is not at all related to the release version, but a range of supported
# API versions. Read TODO_RELEASE in the source tree's root!
MGCP_CLIENT_LIBVERSION=14:0:0
MGCP_CLIENT_LIBVERSION=11:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
@@ -38,8 +40,3 @@ libosmo_mgcp_client_la_LDFLAGS = \
-version-info $(MGCP_CLIENT_LIBVERSION) \
-no-undefined \
$(NULL)
libosmo_mgcp_client_la_LIBADD = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@@ -173,30 +173,6 @@ const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
return osmo_fsm_inst_name(ep->fi);
}
/*! Get "local endpoint name" part of the endpoint name: (local-endpoint-name@domain-name)
*
* \param ep The MGCP Endpoint
* \returns the local endpoint name if found, NULL on error.
*/
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep)
{
static char buf[1024];
const char *sep;
OSMO_ASSERT(ep);
sep = strchr(ep->endpoint, '@');
if (!sep) {
OSMO_STRLCPY_ARRAY(buf, ep->endpoint);
return buf;
}
if (sep - ep->endpoint >= sizeof(buf))
return NULL;
memcpy(buf, ep->endpoint, sep - ep->endpoint);
buf[sep - ep->endpoint] = '\0';
return buf;
}
const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
{
/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
@@ -533,42 +509,10 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
ci->notify.fi ? "" : " (not sending a notification)");
/* Below ordering is a delicate decision:
*
* We want to
* - emit the resulting event to ci->notify.fi,
* - check whether we want to tx the next pending MGCP message.
* Both these steps may terminate (=deallocate) the ep.
* So whichever one goes first may cause a use-after-free in the other.
*
* When dispatching the FSM event, we don't get an rc indicating dealloc of the FSM -- it may deallocate and we
* cannot tell. The common mechanism for that is osmo_fsm_set_dealloc_ctx(OTC_SELECT) and query the still
* allocated FSM state after termination (here we would check 'if (ci->ep != NULL)'), but we cannot assume the
* caller has actually set up an osmo_fsm_set_dealloc_ctx(). At time of writing, e.g. osmo-hnbgw does not use
* it.
*
* In osmo_mgcpc_ep_fsm_check_state_chg_after_response(), we do get an rc: false means FSM has terminated.
* On termination, the ep emits a term event to the FSM's parent.
* That may cause the notify.fi to be terminated in turn, depending on how the caller set things up.
* So: we cannot store notify.fi before, then call osmo_mgcpc_ep_fsm_check_state_chg_after_response(), and then
* emit the event, because notify.fi may have deallocated. We cannot look up whether
* osmo_mgcpc_ep_cancel_notify() has been called, because ci may have deallocated along with ci->ep.
*
* We have to skip emitting below success event in case the ep is now terminated.
* - It may be the final DLCX OK: not a problem, osmo_mgcpc_ep_ci_dlcx() has no notify args on purpose, so we do
* make all callers not set a notify event for DLCX by design. notify.fi should always be NULL when the final
* DLCX OK terminates the local endpoint state.
* - It may also be sudden termination due to a bad problem, in which case we shouldn't emit success.
* The osmo_fsm_inst.parent_term_event should suffice as feedback to the caller.
*/
if (osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi) == false) {
/* false means, the ci->ep has been terminated. */
return;
}
if (ci->notify.fi)
osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
}
/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
@@ -718,11 +662,11 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
*ci = cleared_ci;
LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
if (verb_info)
ci->verb_info = *verb_info;
LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
if (ep->endpoint[0]) {
if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
LOG_CI(ci, LOGL_ERROR,

View File

@@ -19,7 +19,6 @@
*/
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/fsm.h>
@@ -115,10 +114,12 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
.call_id = info->call_id,
.conn_mode = MGCP_CONN_RECV_ONLY,
.ptime = info->ptime,
.codecs_len = info->codecs_len,
.ptmap_len = info->ptmap_len,
.param_present = info->param_present
};
osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
@@ -135,19 +136,10 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
{
bool ip_is_set = info->addr[0] != '\0' &&
strncmp(info->addr, "::", sizeof(info->addr)) != 0 &&
strncmp(info->addr, "0.0.0.0", sizeof(info->addr)) != 0;
if (ip_is_set) {
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP;
mgcp_msg->audio_ip = info->addr;
}
if (info->port) {
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_PORT;
mgcp_msg->audio_port = info->port;
}
if (ip_is_set && info->port)
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT;
mgcp_msg->audio_ip = info->addr;
mgcp_msg->audio_port = info->port;
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
}
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
@@ -171,10 +163,12 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
.audio_ip = mgcp_ctx->conn_peer_local.addr,
.audio_port = mgcp_ctx->conn_peer_local.port,
.ptime = mgcp_ctx->conn_peer_local.ptime,
.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
.param_present = mgcp_ctx->conn_peer_local.param_present
};
osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
@@ -227,7 +221,8 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
mgcp_ctx->conn_peer_local.endpoint);
make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
if (mgcp_ctx->conn_peer_local.port)
add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
@@ -369,21 +364,13 @@ static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
switch (event) {
case EV_MDCX:
msg = make_mdcx_msg(mgcp_ctx);
if (!msg) {
/* make_mdcx_msg() should already have logged the error */
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
return;
}
OSMO_ASSERT(msg);
rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
new_state = ST_MDCX_RESP;
break;
case EV_DLCX:
msg = make_dlcx_msg(mgcp_ctx);
if (!msg) {
/* make_dlcx_msg() should already have logged the error */
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
return;
}
OSMO_ASSERT(msg);
rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
new_state = ST_DLCX_RESP;
break;
@@ -624,72 +611,6 @@ static struct osmo_fsm fsm_mgcp_client = {
.log_subsys = DLMGCP,
};
/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
* that has codecs[] set, apply it to ptmap[] instead. */
static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)
{
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
if (!conn_peer->codecs_len)
return;
/* Before dropping codecs[], codecs[] would indicate the order in which the codecs should appear in SDP. ptmap[]
* would indicate payload type numbers when not using a default payload type number (may omit entries).
* Now, ptmap[] just indicates both at the same time; codecs[] should be empty, and ptmap[] lists all codecs.
* So if any codecs[] are present, recreate ptmap[] in the order of codecs[]. */
ptmap_len = 0;
for (int i = 0; i < conn_peer->codecs_len; i++) {
enum mgcp_codecs codec = conn_peer->codecs[i];
struct ptmap *found = NULL;
/* Look up whether a specific pt was indicated for this codec */
for (int p = 0; p < conn_peer->ptmap_len; p++) {
if (conn_peer->ptmap[p].codec != codec)
continue;
found = &conn_peer->ptmap[p];
break;
}
if (found) {
ptmap[ptmap_len] = *found;
} else {
ptmap[ptmap_len] = (struct ptmap){
.codec = codec,
/* some enum mgcp_codecs correspond to their standard PT nr, so for compat: */
.pt = codec,
};
}
ptmap_len++;
}
/* Are there any entries in the old ptmap that were omitted by codecs[]? */
for (int p = 0; p < conn_peer->ptmap_len; p++) {
bool exists = false;
for (int i = 0; i < ptmap_len; i++) {
if (ptmap_cmp(&ptmap[i], &conn_peer->ptmap[p]))
continue;
exists = true;
break;
}
if (exists)
continue;
if (ptmap_len >= ARRAY_SIZE(ptmap))
break;
/* Not present yet, add it to the end */
ptmap[ptmap_len] = conn_peer->ptmap[p];
ptmap_len++;
}
/* Use the new ptmap[], and clear out legacy codecs[]. */
memcpy(conn_peer->ptmap, ptmap, sizeof(conn_peer->ptmap));
conn_peer->ptmap_len = ptmap_len;
conn_peer->codecs_len = 0;
}
/*! allocate FSM, and create a new connection on the MGW.
* \param[in] mgcp MGCP client descriptor.
* \param[in] parent_fi Parent FSM instance.
@@ -704,7 +625,6 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
struct osmo_fsm_inst *fi;
struct in6_addr ip_test;
mgcp_conn_peer_compat(conn_peer);
OSMO_ASSERT(parent_fi);
OSMO_ASSERT(mgcp);
@@ -744,8 +664,6 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
struct mgcp_ctx *mgcp_ctx = fi->priv;
struct in6_addr ip_test;
mgcp_conn_peer_compat(conn_peer);
OSMO_ASSERT(mgcp_ctx);
OSMO_ASSERT(conn_peer);

View File

@@ -75,11 +75,6 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
pool->mgcp_client_single = mgcp_client;
}
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool)
{
return llist_empty(&pool->member_list);
}
/*! Lookup the selected MGCP client config by its reference number */
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
{
@@ -94,7 +89,7 @@ struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_c
}
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
* pool member that is suitable (is not blocked, has a client with a working link, has a low load). */
* pool member that is suitable (has a client, is not blocked, has a low load). */
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
{
struct mgcp_client_pool_member *pool_member;
@@ -103,15 +98,14 @@ static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_
llist_for_each_entry(pool_member, &pool->member_list, list) {
n_pool_members++;
bool conn_up = pool_member->client && pool_member->client->conn_up;
if (pool_member->blocked == false && conn_up) {
if (pool_member->blocked == false && pool_member->client) {
if (!pool_member_picked)
pool_member_picked = pool_member;
else if (pool_member_picked->refcount > pool_member->refcount)
pool_member_picked = pool_member;
} else {
LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u, link=%u)\n",
__func__, pool_member->nr, pool_member->blocked, !!pool_member->client, conn_up);
LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u)\n",
__func__, pool_member->nr, pool_member->blocked, !!pool_member->client);
}
}

View File

@@ -1,5 +1,5 @@
/* MGCP client interface to quagga VTY */
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2011 by Holger Hans Peter Freyther
@@ -28,7 +28,6 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/misc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/timer.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
@@ -49,43 +48,19 @@ static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
static struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
{
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
return vty->index;
/* Global single MGCP config, deprecated: */
vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
"You should consider reading the User Manual and migrating to 'mgw' node.%s",
"You should consider reading User Manual and migrating to 'mgw' node.%s",
VTY_NEWLINE);
return global_mgcp_client_conf;
}
static struct mgcp_client *get_mgcp_client(struct vty *vty)
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
struct mgcp_client_pool_member *pool_member;
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node) {
llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
/* Find matching the conf pointer: */
if (&pool_member->conf != conf)
continue;
return pool_member->client;
}
}
/* Global single MGCP config, deprecated: */
vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
"You should consider reading the User Manual and migrating to 'mgw' node.%s",
VTY_NEWLINE);
/* There's no way to obtain the struct mgcp_client in old interface, but anyway it's deprecated. */
return NULL;
}
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
"local-ip " VTY_IPV46_CMD,
"local bind to connect to MGW from\n"
@@ -305,91 +280,6 @@ ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
DEFUN(cfg_mgw_mgw_keepalive_req_interval,
cfg_mgw_mgw_keepalive_req_interval_cmd,
"keepalive request-interval <0-4294967295>",
"Monitor if the MGCP link against MGW is still usable\n"
"Send an MGCP command to the MGW at given interval if no other commands are sent\n"
"The interval at which send MGCP commands (s), 0 to disable\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
struct mgcp_client *mgcp = get_mgcp_client(vty);
conf->keepalive.req_interval_sec = atoi(argv[0]);
if (!mgcp)
return CMD_SUCCESS;
/* If client already exists, apply the change immediately if possible: */
mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
if (mgcp->iofd) { /* UDP MGCP socket connected */
if (mgcp->actual.keepalive.req_interval_sec > 0) {
/* Re-schedule: */
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
} else {
if (osmo_timer_pending(&mgcp->keepalive_tx_timer))
osmo_timer_del(&mgcp->keepalive_tx_timer);
/* Assume link is UP by default, so that this MGW can be selected: */
mgcp->conn_up = true;
}
} /* else: wait until connect() to do first scheduling */
return CMD_SUCCESS;
}
DEFUN(cfg_mgw_mgw_keepalive_req_endpoint,
cfg_mgw_mgw_keepalive_req_endpoint_cmd,
"keepalive request-endpoint NAME",
"Monitor if the MGCP link against MGW is still usable\n"
"Use a given endpoint name when sending an MGCP command to the MGW for keepalive purposes\n"
"The name of the endpoint to use\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
struct mgcp_client *mgcp = get_mgcp_client(vty);
OSMO_STRLCPY_ARRAY(conf->keepalive.req_endpoint_name, argv[0]);
if (!mgcp)
return CMD_SUCCESS;
/* If client already exists, apply the change immediately if possible: */
OSMO_STRLCPY_ARRAY(mgcp->actual.keepalive.req_endpoint_name, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgw_mgw_keepalive_timeout,
cfg_mgw_mgw_keepalive_timeout_cmd,
"keepalive timeout <0-4294967295>",
"Monitor if the MGCP link against MGW is still usable\n"
"Consider the link to the MGW to be down after time without receiving any message from it\n"
"The timeout (s), 0 to disable\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
struct mgcp_client *mgcp = get_mgcp_client(vty);
conf->keepalive.timeout_sec = atoi(argv[0]);
if (!mgcp)
return CMD_SUCCESS;
/* If client already exists, apply the change immediately if possible: */
mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
if (mgcp->iofd) { /* UDP MGCP socket connected */
if (mgcp->actual.keepalive.timeout_sec > 0) {
/* Re-schedule: */
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
} else {
if (osmo_timer_pending(&mgcp->keepalive_rx_timer))
osmo_timer_del(&mgcp->keepalive_rx_timer);
/* Assume link is UP by default, so that this MGW can be selected: */
mgcp->conn_up = true;
}
} /* else: wait until connect() to do first scheduling */
return CMD_SUCCESS;
}
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
{
const char *addr;
@@ -427,17 +317,6 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
if (conf->keepalive.req_interval_sec != 0)
vty_out(vty, "%s%skeepalive request-interval %u%s", indent, mgw_prefix,
conf->keepalive.req_interval_sec, VTY_NEWLINE);
if (strncmp(conf->keepalive.req_endpoint_name, MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP,
sizeof(conf->keepalive.req_endpoint_name)) != 0)
vty_out(vty, "%s%skeepalive request-endpoint %s%s", indent, mgw_prefix,
conf->keepalive.req_endpoint_name, VTY_NEWLINE);
if (conf->keepalive.timeout_sec != 0)
vty_out(vty, "%s%skeepalive timeout %u%s", indent, mgw_prefix,
conf->keepalive.timeout_sec, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -468,9 +347,6 @@ static void vty_init_common(void *talloc_ctx, int node)
install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
install_lib_element(node, &cfg_mgw_mgw_keepalive_req_interval_cmd);
install_lib_element(node, &cfg_mgw_mgw_keepalive_req_endpoint_cmd);
install_lib_element(node, &cfg_mgw_mgw_keepalive_timeout_cmd);
osmo_fsm_vty_add_cmds();
}
@@ -677,13 +553,8 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
}
llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
const struct mgcp_client *cli = pool_member->client;
vty_out(vty, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
vty_out(vty, "%% MGCP link: %s,%s%s",
cli && cli->iofd ? "connected" : "disconnected",
cli && cli->conn_up ?
((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
"DOWN",
vty_out(vty, "%% mgcp-client: %s%s", pool_member->client ? "connected" : "disconnected",
VTY_NEWLINE);
vty_out(vty, "%% service: %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
vty_out(vty, "%% ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);

View File

@@ -16,6 +16,12 @@ AM_CFLAGS = \
$(NULL)
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOTRAU_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)

View File

@@ -276,6 +276,87 @@ error:
return -EINVAL;
}
/* Check if the given codec is applicable on the specified endpoint
* Helper function for mgcp_codec_decide() */
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
{
/* A codec name must be set, if not, this might mean that the codec
* (payload type) that was assigned is unknown to us so we must stop
* here. */
if (!strlen(codec->subtype_name))
return false;
/* FIXME: implement meaningful checks to make sure that the given codec
* is compatible with the given endpoint */
return true;
}
/*! Decide for one suitable codec
* \param[in] conn related rtp-connection.
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_end *rtp;
unsigned int i;
struct mgcp_endpoint *endp;
bool codec_assigned = false;
endp = conn->conn->endp;
rtp = &conn->end;
/* This function works on the results the SDP/LCO parser has extracted
* from the MGCP message. The goal is to select a suitable codec for
* the given connection. When transcoding is available, the first codec
* from the codec list is taken without further checking. When
* transcoding is not available, then the choice must be made more
* carefully. Each codec in the list is checked until one is found that
* is rated compatible. The rating is done by the helper function
* is_codec_compatible(), which does the actual checking. */
for (i = 0; i < rtp->codecs_assigned; i++) {
/* When no transcoding is available, avoid codecs that would
* require transcoding. */
if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
continue;
}
rtp->codec = &rtp->codecs[i];
codec_assigned = true;
break;
}
/* FIXME: To the reviewes: This is problematic. I do not get why we
* need to reset the packet_duration_ms depending on the codec
* selection. I thought it were all 20ms? Is this to address some
* cornercase. (This piece of code was in the code path before,
* together with the note: "TODO/XXX: Store this per codec and derive
* it on use" */
if (codec_assigned) {
if (rtp->maximum_packet_time >= 0
&& rtp->maximum_packet_time * rtp->codec->frame_duration_den >
rtp->codec->frame_duration_num * 1500)
rtp->packet_duration_ms = 0;
return 0;
}
return -EINVAL;
}
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
{
if (codec->param_present == false)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
if (strcmp(codec->subtype_name, "AMR") != 0)
return false;
return true;
}
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
* Media Type Registration":
@@ -295,15 +376,10 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
return codec->param.amr_octet_aligned;
}
/* Compare two codecs, all parameters must match up */
/* Compare two codecs, all parameters must match up, except for the payload type
* number. */
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
* exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
* payload type numbers. Also the audio_name is not checked since it is already parsed into subtype_name, rate,
* and channels, which are checked. */
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
return false;
if (codec_a->rate != codec_b->rate)
return false;
if (codec_a->channels != codec_b->channels)
@@ -312,172 +388,61 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
return false;
if (codec_a->frame_duration_den != codec_b->frame_duration_den)
return false;
/* AMR payload may be formatted in two different payload formats, it is still the same codec but since the
* formatting of the payload is different, conversation is required, so we must treat it as a different
* codec here. */
if (strcmp(codec_a->subtype_name, "AMR") == 0) {
if (mgcp_codec_amr_is_octet_aligned(codec_a) != mgcp_codec_amr_is_octet_aligned(codec_b))
return false;
}
return true;
}
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
* translate between different payload formats as long as the encoded voice data itself does not change.
* Therefore we must insist on equal codecs but still allow different payload formatting. */
/* In 3G IuUP, AMR may be encapsulated in IuFP, this means even though the codec name and negotiated rate is
* different, the formatting can still be converted by OsmoMGW. Therefore we won't insist on equal
* subtype_name and rate if we detect IuFP and AMR is used on the same tandem. */
if (strcmp(codec_a->subtype_name, "AMR") == 0 && strcmp(codec_b->subtype_name, "VND.3GPP.IUFP") == 0)
goto iufp;
if (strcmp(codec_a->subtype_name, "VND.3GPP.IUFP") == 0 && strcmp(codec_b->subtype_name, "AMR") == 0)
goto iufp;
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
return false;
if (codec_a->rate != codec_b->rate)
return false;
iufp:
if (codec_a->channels != codec_b->channels)
return false;
if (codec_a->frame_duration_num != codec_b->frame_duration_num)
return false;
if (codec_a->frame_duration_den != codec_b->frame_duration_den)
return false;
/* Note: AMR allows to set the RTP payload format to octet-aligned or bandwith-efficient (octet-aligned=0)
* via SDP. This difference concerns payload format only, but not the actual codec. It is not a difference
* within the meaning of this function. */
return true;
}
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
/*! Translate a given payload type number that belongs to the packet of a
* source connection to the equivalent payload type number that matches the
* configuration of a destination connection.
* \param[in] conn_src related source rtp-connection.
* \param[in] conn_dst related destination rtp-connection.
* \param[in] payload_type number from the source packet or source connection.
* \returns translated payload type number on success, -EINVAL on failure. */
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type)
{
struct mgcp_rtp_end *rtp_end;
struct mgcp_rtp_end *rtp_src;
struct mgcp_rtp_end *rtp_dst;
struct mgcp_rtp_codec *codec_src = NULL;
struct mgcp_rtp_codec *codec_dst = NULL;
unsigned int i;
unsigned int codecs_assigned;
rtp_end = &conn->end;
rtp_src = &conn_src->end;
rtp_dst = &conn_dst->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codecs_assigned = rtp_end->codecs_assigned;
/* Find the codec information that is used on the source side */
codecs_assigned = rtp_src->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_same(codec, &rtp_end->codecs[i])) {
return &rtp_end->codecs[i];
if (payload_type == rtp_src->codecs[i].payload_type) {
codec_src = &rtp_src->codecs[i];
break;
}
}
if (!codec_src)
return -EINVAL;
return NULL;
}
/* For a given codec, find a convertible codec in the given connection. */
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int codecs_assigned;
struct mgcp_rtp_codec *codec_convertible = NULL;
rtp_end = &conn->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codec_convertible = mgcp_codec_find_same(conn, codec);
if (codec_convertible)
return codec_convertible;
/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
* payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
codecs_assigned = rtp_end->codecs_assigned;
/* Use the codec information from the source and try to find the
* equivalent of it on the destination side */
codecs_assigned = rtp_dst->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
codec_convertible = &rtp_end->codecs[i];
if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
codec_dst = &rtp_dst->codecs[i];
break;
}
}
return codec_convertible;
}
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
* a tentative decision is made.
* \param[inout] conn_src related rtp-connection.
* \param[inout] conn_dst related destination rtp-connection (NULL if not present).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
{
unsigned int i;
/* In case no destination connection is available (yet), or in case the destination connection exists but has
* no codecs assigned, we are forced to make a simple tentative decision:
* We just use the first codec of the source connection (conn_src) */
OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
if (conn_src->end.codecs_assigned >= 1) {
conn_src->end.codec = &conn_src->end.codecs[0];
return 0;
} else
return -EINVAL;
}
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
* of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
* required. */
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src);
if (codec_conn_dst) {
/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
* sides. We now set this codec on both connections. */
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
return 0;
}
}
/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
* to convert. */
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src);
if (codec_conn_dst) {
/* We found the a codec that we can convert to. Set each side to its codec. */
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
return 0;
}
}
if (conn_dst->end.codecs_assigned)
conn_dst->end.codec = &conn_dst->end.codecs[0];
else
if (!codec_dst)
return -EINVAL;
if (conn_src->end.codecs_assigned)
conn_src->end.codec = &conn_src->end.codecs[0];
else
return -EINVAL;
return 0;
}
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
{
if (codec->param_present == false)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
if (strcmp(codec->subtype_name, "AMR") != 0)
return false;
return true;
return codec_dst->payload_type;
}
/* Find the payload type number configured for a specific codec by SDP.
@@ -487,7 +452,8 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
* \param subtype_name SDP codec name without parameters (e.g. "AMR").
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
* with incrementing match_nr.
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found.
*/
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr)
{
@@ -503,26 +469,3 @@ const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn
}
return NULL;
}
/*! Lookup a codec that is assigned to a connection by its payload type number.
* \param[in] conn related rtp-connection.
* \param[in] payload_type number of the codec to look up.
* \returns pointer to codec struct on success, NULL on failure. */
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
{
struct mgcp_rtp_end *rtp_end = &conn->end;
unsigned int codecs_assigned = rtp_end->codecs_assigned;
struct mgcp_rtp_codec *codec = NULL;
size_t i;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (payload_type == rtp_end->codecs[i].payload_type) {
codec = &rtp_end->codecs[i];
break;
}
}
return codec;
}

View File

@@ -106,10 +106,12 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
/* backpointer to the generic part of the connection */
conn->u.rtp.conn = conn;
end->rtp = NULL;
end->rtcp = NULL;
end->rtp.fd = -1;
end->rtcp.fd = -1;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;
talloc_free(end->fmtp_extra);
end->fmtp_extra = NULL;
/* Set default values */
end->frames_per_packet = 0; /* unknown */
@@ -171,8 +173,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
struct mgcp_conn *conn;
int rc;
/* Do not allow more than the maximum number of connections */
if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns)
/* Do not allow more then two connections */
if (llist_count(&endp->conns) >= endp->type->max_conns)
return NULL;
/* Create new connection and add it to the list */
@@ -356,37 +358,53 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
{
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
char ipbuf[INET6_ADDRSTRLEN];
struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
if (!conn)
return "NULL";
if (!conn) {
snprintf(str, sizeof(str), "(null connection)");
return str;
}
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
conn->name,
mgcp_conn_rtp_type_name(conn->type),
conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf) ? : "NULL",
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
conn->u.rtp.end.local_addr ? : "NULL",
conn->u.rtp.end.local_port);
switch (conn->u.rtp.type) {
case MGCP_RTP_DEFAULT:
/* Dump RTP connection */
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
"rtp:%u rtcp:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
ntohs(conn->u.rtp.end.rtcp_port));
break;
case MGCP_RTP_OSMUX:
OSMO_STRBUF_PRINTF(sb, " CID=%u", conn->u.rtp.osmux.local_cid);
snprintf(str, sizeof(str), "(%s/osmux, id:0x%s, ip:%s, "
"port:%u CID:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
conn->u.rtp.osmux.local_cid);
break;
case MGCP_RTP_IUUP:
snprintf(str, sizeof(str), "(%s/iuup, id:0x%s, ip:%s, "
"port:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
break;
default:
/* Should not happen, we should be able to dump
* every possible connection type. */
snprintf(str, sizeof(str), "(unknown conn_rtp connection type %u)",
conn->u.rtp.type);
break;
}
OSMO_STRBUF_PRINTF(sb, ")");
break;
default:
/* Should not happen, we should be able to dump
* every possible connection type. */
return "(unknown connection type)";
snprintf(str, sizeof(str), "(unknown connection type)");
break;
}
return str;
@@ -423,10 +441,3 @@ struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
}
const struct value_string mgcp_conn_rtp_type_names[] = {
{ MGCP_RTP_DEFAULT, "rtp" },
{ MGCP_RTP_OSMUX, "osmux" },
{ MGCP_RTP_IUUP, "iuup" },
{}
};

View File

@@ -222,7 +222,7 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
osmo_i460_mux_enqueue(endp->e1.schan, msg);
}
/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */
static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
unsigned int num_bits)
{
@@ -301,6 +301,7 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
msgb_free(msg);
return;
skip:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
@@ -308,8 +309,8 @@ skip:
return;
}
/* handle outgoing E1 traffic */
static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
/* Function to handle outgoing E1 traffic */
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
{
struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
uint8_t *ptr;
@@ -324,7 +325,7 @@ static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
#endif
/* Hand data over to the E1 stack */
e1inp_ts_send_raw(ts, msg);
msgb_enqueue(&ts->raw.tx_queue, msg);
return;
}
@@ -358,17 +359,19 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
/* Trigger sending of pending E1 traffic */
e1_send_ts_frame(ts, trunk);
e1_send(ts, trunk);
/* e1inp_rx_ts(), the caller of this callback does not free() msgb. */
/* e1inp_rx_ts() does not free() msgb */
msgb_free(msg);
}
static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
{
/*! One E1 timeslot may serve multiple I.460 subslots. The timeslot is opened as soon as an I.460 subslot is
* opened and will stay open until the last I.460 subslot is closed (see e1_close below). This function must
* be called any time a new I.460 subslot is opened in order to maintain constancy of the ts_usecount counter. */
/*! Each timeslot needs only to be configured once. The Timeslot then
* stays open and permanently receives data. It is then up to the
* I.460 demultiplexer to add/remove subchannels as needed. It is
* allowed to call this function multiple times since we check if the
* timeslot is already configured. */
struct e1inp_line *e1_line;
int rc;
@@ -376,14 +379,12 @@ static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
cfg = trunk->cfg;
if (trunk->e1.ts_usecount[ts_nr - 1] > 0) {
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up and in use by %u subslot(s), using it as it is...\n",
ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
trunk->e1.ts_usecount[ts_nr - 1]++;
if (trunk->e1.ts_in_use[ts_nr - 1]) {
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
return 0;
}
/* Find E1 line */
/* Get E1 line */
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
if (!e1_line) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
@@ -400,61 +401,12 @@ static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
}
rc = e1inp_line_update(e1_line);
if (rc < 0) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", ts_nr);
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
return -EINVAL;
}
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
trunk->e1.ts_usecount[ts_nr - 1]++;
OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 1);
return 0;
}
static int e1_close(struct mgcp_trunk *trunk, uint8_t ts_nr)
{
/* See also comment above (e1_open). This function must be called any time an I.460 subslot is closed */
struct e1inp_line *e1_line;
int rc;
OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
cfg = trunk->cfg;
if (trunk->e1.ts_usecount[ts_nr - 1] > 1) {
trunk->e1.ts_usecount[ts_nr - 1]--;
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u still in use by %u other subslot(s), leaving it open...\n",
ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
return 0;
} else if (trunk->e1.ts_usecount[ts_nr - 1] == 0) {
/* This should not be as it means we close the timeslot too often. */
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "E1 timeslot %u already closed, leaving it as it is...\n", ts_nr);
return -EINVAL;
}
/* Find E1 line */
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
if (!e1_line) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
trunk->e1.vty_line_nr);
return -EINVAL;
}
/* Release E1 timeslot */
rc = e1inp_ts_config_none(&e1_line->ts[ts_nr - 1], e1_line);
if (rc < 0) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to disable E1 timeslot %u.\n", ts_nr);
return -EINVAL;
}
rc = e1inp_line_update(e1_line);
if (rc < 0) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", trunk->e1.vty_line_nr);
return -EINVAL;
}
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u closed.\n", ts_nr);
trunk->e1.ts_usecount[ts_nr - 1]--;
OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 0);
trunk->e1.ts_in_use[ts_nr - 1] = true;
return 0;
}
@@ -465,21 +417,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
{
if (strcmp(sdp_subtype_name, "GSM") == 0)
return OSMO_TRAU16_FT_FR;
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU16_FT_EFR;
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
if (i460_rate == OSMO_I460_RATE_16k)
return OSMO_TRAU16_FT_HR;
if (i460_rate == OSMO_I460_RATE_8k)
return OSMO_TRAU8_SPEECH;
LOGPENDP(endp, DE1, LOGL_ERROR,
"E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
return OSMO_TRAU_FT_NONE;
}
if (strcmp(sdp_subtype_name, "AMR") == 0) {
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
return OSMO_TRAU16_FT_HR;
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -497,11 +439,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
}
}
return OSMO_TRAU16_FT_AMR;
} else {
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_FT_NONE;
}
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_FT_NONE;
}
/* Determine a suitable TRAU frame type for a given codec */
@@ -510,21 +452,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
{
if (strcmp(sdp_subtype_name, "GSM") == 0)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
if (i460_rate == OSMO_I460_RATE_16k)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (i460_rate == OSMO_I460_RATE_8k)
return OSMO_TRAU_SYNCP_8_HR;
LOGPENDP(endp, DE1, LOGL_ERROR,
"E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
if (strcmp(sdp_subtype_name, "AMR") == 0) {
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
return OSMO_TRAU_SYNCP_8_HR;
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -542,11 +474,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
}
}
return OSMO_TRAU_SYNCP_16_FR_EFR;
} else {
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
/* Find out if a given TRAU frame type is AMR */
@@ -564,7 +496,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
}
}
/*! Equip E1 endpoint with I.460 mux and E1 timeslot resources.
/*! Equip E1 endpoint with I.460 mux resources.
* \param[in] endp endpoint to equip
* \param[in] ts E1 timeslot number.
* \param[in] ss E1 subslot number.
@@ -585,7 +517,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
endp->e1.last_amr_ft = AMR_4_75;
/* Set up E1 line / timeslot */
rc = e1_open(endp->trunk, ts);
rc = e1_init(endp->trunk, ts);
if (rc != 0)
return -EINVAL;
@@ -672,15 +604,9 @@ void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
}
/*! Remove E1 resources from endpoint
* \param[in] endp endpoint to release.
* \param[in] ts E1 timeslot number. */
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
* \param[in] endp endpoint to release. */
void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
{
/* Guard against multiple calls. In case we don't see a subchannel anymore we can safely assume that all work
* is done. */
if (!(endp->e1.schan || endp->e1.trau_rtp_st || endp->e1.trau_sync_fi))
return;
LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
if (endp->e1.schan)
@@ -689,10 +615,8 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
talloc_free(endp->e1.trau_rtp_st);
if (endp->e1.trau_sync_fi)
osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
memset(&endp->e1, 0, sizeof(endp->e1));
/* Close E1 timeslot */
e1_close(endp->trunk, ts);
memset(&endp->e1, 0, sizeof(endp->e1));
}
/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.

View File

@@ -38,6 +38,7 @@
const struct mgcp_endpoint_typeset ep_typeset = {
/* Specify endpoint properties for RTP endpoint */
.rtp = {
.max_conns = 2,
.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
},
@@ -109,6 +110,36 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
return endp;
}
/*! release endpoint, all open connections are closed.
* \param[in] endp endpoint to release */
void mgcp_endp_release(struct mgcp_endpoint *endp)
{
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
/* Normally this function should only be called when
* all connections have been removed already. In case
* that there are still connections open (e.g. when
* RSIP is executed), free them all at once. */
mgcp_conn_free_all(endp);
/* We must only decrement the stat item when the endpoint as actually
* claimed. An endpoint is claimed when a call-id is set */
if (endp->callid)
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
TRUNK_STAT_ENDPOINTS_USED), 1);
/* Reset endpoint parameters and states */
talloc_free(endp->callid);
endp->callid = NULL;
talloc_free(endp->local_options.string);
endp->local_options.string = NULL;
talloc_free(endp->local_options.codec);
endp->local_options.codec = NULL;
if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
mgcp_e1_endp_release(endp);
}
/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
* "ds/e1-") and write the epname without the prefix back to the memory
* pointed at by epname. (per trunk the prefix is the same for all endpoints,
@@ -156,6 +187,7 @@ static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
}
}
/*! Convert all characters in epname to lowercase and strip trunk prefix and
* endpoint name suffix (domain name) from epname. The result is written to
* to the memory pointed at by epname_stripped. The expected size of the
@@ -228,17 +260,6 @@ bool mgcp_endp_is_wildcarded(const char *epname)
return false;
}
/*! Check if the given epname refers to a "null" endpoint.
* \param[in] epname endpoint name to check
* \returns true if epname refers to "null"" endpoint, else false. */
bool mgcp_endp_is_null(const char *epname)
{
if (strncasecmp(epname, "null@", 5) == 0)
return true;
return false;
}
/*! Find an endpoint by its name on a specified trunk.
* \param[out] cause pointer to store cause code, can be NULL.
* \param[in] epname endpoint name to lookup.
@@ -654,36 +675,3 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
if (llist_empty(&endp->conns))
mgcp_endp_release(endp);
}
/*! release endpoint, all open connections are closed.
* \param[in] endp endpoint to release */
void mgcp_endp_release(struct mgcp_endpoint *endp)
{
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
/* Normally this function should only be called when
* all connections have been removed already. In case
* that there are still connections open (e.g. when
* RSIP is executed), free them all at once. */
mgcp_conn_free_all(endp);
/* We must only decrement the stat item when the endpoint as actually
* claimed. An endpoint is claimed when a call-id is set */
if (endp->callid)
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
TRUNK_STAT_ENDPOINTS_USED), 1);
/* Reset endpoint parameters and states */
talloc_free(endp->callid);
endp->callid = NULL;
talloc_free(endp->local_options.string);
endp->local_options.string = NULL;
talloc_free(endp->local_options.codec);
endp->local_options.codec = NULL;
if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
uint8_t ts = e1_ts_nr_from_epname(endp->name);
mgcp_e1_endp_release(endp, ts);
}
}

View File

@@ -311,6 +311,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
};
rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
msgb_free(msg);
return rc;
}
@@ -468,7 +469,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
int buflen = msgb_length(msg);
char *dest_name;
int rc;
int len;
OSMO_ASSERT(conn_src);
OSMO_ASSERT(conn_dst);
@@ -505,7 +506,6 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
rtp_state->alt_rtp_tx_sequence++;
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
@@ -513,17 +513,19 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
if (rc < 0)
return rc;
if (len <= 0)
return len;
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
return len;
}
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
@@ -638,7 +640,7 @@ free_ret:
}
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
* peer and send it down the IuUP layer towards the destination as IuUP/RTP. Takes ownership of msg. */
* peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
{
struct osmo_iuup_rnl_prim *irp;

View File

@@ -75,7 +75,7 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
}
/*! Parse connection mode.
* \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
* \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
* \param[in] endp pointer to endpoint (only used for log output)
* \param[out] associated connection to be modified accordingly
* \returns 0 on success, -1 on error */
@@ -100,8 +100,6 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
conn->mode = MGCP_CONN_RECV_SEND;
else if (strcasecmp(mode, "sendonly") == 0)
conn->mode = MGCP_CONN_SEND_ONLY;
else if (strcasecmp(mode, "confecho") == 0)
conn->mode = MGCP_CONN_CONFECHO;
else if (strcasecmp(mode, "loopback") == 0)
conn->mode = MGCP_CONN_LOOPBACK;
else {

View File

@@ -4,7 +4,6 @@
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -71,18 +70,6 @@ void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
}
/* wrapper around libosmocore msgb_copy_c, which [at least before libosmocore.git Change-Id
* I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5] doesn't copy the cb */
static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const char *name)
{
struct msgb *msg2 = msgb_copy_c(ctx, msg, name);
if (OSMO_UNLIKELY(!msg2))
return NULL;
memcpy(msg2->cb, msg->cb, sizeof(msg2->cb));
return msg2;
}
static int rx_rtp(struct msgb *msg);
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
@@ -417,12 +404,15 @@ static int align_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
* \param[in] associated endpoint.
* \param[in] destination RTP end.
* \param[in,out] msg message bufffer containing data. Function might change length.
* \param[in,out] pointer to buffer with voice data.
* \param[in] voice data length.
* \param[in] maximum size of caller provided voice data buffer.
* \returns ignores input parameters, return always 0. */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct msgb *msg)
char *data, int *len, int buf_size)
{
LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
return 0;
}
@@ -439,6 +429,18 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
return 0;
}
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
const struct mgcp_rtp_codec **codec,
const char **fmtp_extra,
struct mgcp_conn_rtp *conn)
{
LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s using format defaults\n",
mgcp_conn_dump(conn->conn));
*codec = conn->end.codec;
*fmtp_extra = conn->end.fmtp_extra;
}
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state, const uint16_t seq,
const int32_t transit, const uint32_t ssrc,
@@ -490,24 +492,28 @@ void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp,
/* There may be different payload type numbers negotiated for two connections.
* Patch the payload type of an RTP packet so that it uses the payload type
* of the codec that is set for the destination connection (conn_dst) */
static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
* that is valid for the destination connection (conn_dst) */
static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
{
struct rtp_hdr *rtp_hdr;
uint8_t pt_in;
int pt_out;
if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "RTP packet too short (%u < %zu)\n",
LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
msgb_length(msg), sizeof(struct rtp_hdr));
return -EINVAL;
}
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
if (!conn_dst->end.codec) {
LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
pt_in = rtp_hdr->payload_type;
pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
if (pt_out < 0)
return -EINVAL;
}
rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
rtp_hdr->payload_type = (uint8_t) pt_out;
return 0;
}
@@ -795,18 +801,16 @@ static int amr_oa_check(char *data, int len)
/* Forward data to a debug tap. This is debug function that is intended for
* debugging the voice traffic with tools like gstreamer */
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg)
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
{
int rc;
if (!tap->enabled)
return;
struct msgb *msg2 = msgb_copy(msg, "RTP TAP Tx");
if (!msg2)
return;
rc = sendto(fd, msgb_data(msg), msgb_length(msg), 0, (struct sockaddr *)&tap->forward,
sizeof(tap->forward));
rc = osmo_iofd_sendto_msgb(iofd, msg2, 0, &tap->forward);
if (rc < 0)
LOGP(DRTP, LOGL_ERROR,
"Forwarding tapped (debug) voice data failed.\n");
@@ -834,27 +838,32 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
{
char ipbuf[INET6_ADDRSTRLEN];
if (osmo_sockaddr_is_any(&conn->end.addr) != 0 ||
osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
if (mgcp_conn_rtp_is_iuup(conn) && !conn->iuup.configured) {
/* Allow IuUP Initialization to get through even if we don't have a remote address set yet.
* This is needed because hNodeB doesn't announce its IuUP remote IP addr to the MGCP client
* (RAB Assignment Response at HNBGW) until it has gone through IuUP Initialization against
* this MGW here. Hence the MGW may not yet know the remote IuUP address and port at the time
* of receiving IuUP Initialization from the hNodeB.
*/
LOGPCONN(conn->conn, DRTP, LOGL_INFO,
"Rx RTP from %s: allowing unknown src for IuUP Initialization\n",
osmo_sockaddr_to_str(addr));
if (osmo_sockaddr_is_any(&conn->end.addr) != 0) {
switch (conn->conn->mode) {
case MGCP_CONN_LOOPBACK:
/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
* message received. We currently hackishly accomplish that by putting the endpoint in
* loopback mode and patching over the looped back RTP message to make it look like an
* ack. We don't know the femto cell's IP address and port until the RAB Assignment
* Response is received, but the nano3G expects an IuUP Initialization Ack before it even
* sends the RAB Assignment Response. Hence, if the remote address is 0.0.0.0 and the
* MGCP port is in loopback mode, allow looping back the packet to any source. */
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"In loopback mode and remote address not set:"
" allowing data from address: %s\n",
osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
return 0;
default:
/* Receiving early media before the endpoint is configured. Instead of logging
* this as an error that occurs on every call, keep it more low profile to not
* confuse humans with expected errors. */
LOGPCONN(conn->conn, DRTP, LOGL_INFO,
"Rx RTP from %s, but remote address not set:"
" dropping early media\n",
osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
return -1;
}
/* Receiving early media before the endpoint is configured. Instead of logging
* this as an error that occurs on every call, keep it more low profile to not
* confuse humans with expected errors. */
LOGPCONN(conn->conn, DRTP, LOGL_INFO,
"Rx RTP from %s, but remote address not set: dropping early media\n",
osmo_sockaddr_to_str(addr));
return -1;
}
/* Note: Check if the inbound RTP data comes from the same host to
@@ -866,8 +875,11 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
memcmp(&conn->end.addr.u.sin6.sin6_addr, &addr->u.sin6.sin6_addr,
sizeof(struct in6_addr)))) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"data from wrong src %s, expected IP Address %s. Packet tossed.\n",
osmo_sockaddr_to_str(addr), osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
"data from wrong address: %s, ",
osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
return -1;
}
@@ -878,9 +890,12 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"data from wrong src %s, expected port: %u for RTP or %u for RTCP. Packet tossed.\n",
osmo_sockaddr_to_str(addr), osmo_sockaddr_port(&conn->end.addr.u.sa),
ntohs(conn->end.rtcp_port));
"data from wrong source port: %d, ",
osmo_sockaddr_port(&addr->u.sa));
LOGPC(DRTP, LOGL_ERROR,
"expected: %d for RTP or %d for RTCP\n",
osmo_sockaddr_port(&conn->end.addr.u.sa), ntohs(conn->end.rtcp_port));
LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
return -1;
}
@@ -978,7 +993,7 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
return 0;
}
/*! Dispatch msg bridged from the sister conn in the endpoint. Takes ownership of msgb.
/*! Dispatch msg bridged from the sister conn in the endpoint.
* \param[in] conn_dst The destination conn that should handle and transmit the content to
* its peer outside MGW.
* \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
@@ -1000,10 +1015,8 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
/* Before we try to deliver the packet, we check if the destination
* port and IP-Address make sense at all. If not, we will be unable
* to deliver the packet. */
if (check_rtp_destin(conn_dst) != 0) {
msgb_free(msg);
if (check_rtp_destin(conn_dst) != 0)
return -1;
}
/* Depending on the RTP connection type, deliver the RTP packet to the
* destination connection. */
@@ -1038,46 +1051,39 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
* be discarded, this should not happen, normally the MGCP type
* should be properly set */
LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
msgb_free(msg);
return -1;
}
/*! send message buffer via udp socket. If it succeeds, it takes ownership of the msgb and internally calls
* msgb_free() after the aynchronous sendto() completes. In case of error, the msgb is still owned by the
* caller and must be free'd accordingly.
* \param[in] iofd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] msg message buffer that holds the data to be send.
* \returns 0 in case of success (takes msgb ownership), -1 on error (doesn't take msgb ownership). */
static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, struct msgb *msg)
{
LOGP(DRTP, LOGL_DEBUG, "sending %d bytes length packet to %s ...\n", msgb_length(msg),
osmo_sockaddr_to_str(addr));
return osmo_iofd_sendto_msgb(iofd, msg, 0, addr);
}
/*! send udp packet from raw buffer/length.
* \param[in] iofd associated file descriptor.
/*! send udp packet.
* \param[in] fd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] buf buffer that holds the data to be send.
* \param[in] len length of the data to be sent.
* \returns 0 in case of success, -1 on error. */
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len)
* \returns bytes sent, -1 on error. */
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
{
struct msgb *msg = msgb_alloc_c(iofd, len, "mgcp_udp_send");
if (!msg)
return -ENOMEM;
memcpy(msg->tail, buf, len);
msgb_put(msg, len);
char ipbuf[INET6_ADDRSTRLEN];
size_t addr_len;
return mgcp_udp_send_msg(iofd, addr, msg);
LOGP(DRTP, LOGL_DEBUG,
"sending %i bytes length packet to %s:%u ...\n", len,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
osmo_sockaddr_port(&addr->u.sa));
if (addr->u.sa.sa_family == AF_INET6) {
addr_len = sizeof(addr->u.sin6);
} else {
addr_len = sizeof(addr->u.sin);
}
return sendto(fd, buf, len, 0, &addr->u.sa, addr_len);
}
/*! send RTP dummy packet (to keep NAT connection open).
* \param[in] endp mcgp endpoint that holds the RTP connection.
* \param[in] conn associated RTP connection.
* \returns 0 in case of success, -1 on error. */
* \returns bytes sent, -1 on error. */
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int rc;
@@ -1099,7 +1105,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
if (mgcp_conn_rtp_is_iuup(conn))
rc = mgcp_conn_iuup_send_dummy(conn);
else
rc = mgcp_udp_send(conn->end.rtp, &conn->end.addr, rtp_dummy_payload, sizeof(rtp_dummy_payload));
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
goto failed;
@@ -1110,10 +1117,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
was_rtcp = 1;
rtcp_addr = conn->end.addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
rc = mgcp_udp_send(conn->end.rtcp, &rtcp_addr,
rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == 0)
if (rc >= 0)
return rc;
failed:
@@ -1124,14 +1131,15 @@ failed:
return -1;
}
/*! Send RTP/RTCP data to a specified destination connection. Takes ownership of msg.
/*! Send RTP/RTCP data to a specified destination connection.
* \param[in] endp associated endpoint (for configuration, logging).
* \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
* \param[in] addr spoofed source address (set to NULL to disable).
* \param[in] msg message buffer that contains the RTP/RTCP data.
* \param[in] spoofed source address (set to NULL to disable).
* \param[in] buf buffer that contains the RTP/RTCP data.
* \param[in] len length of the buffer that contains the RTP/RTCP data.
* \param[in] conn_src associated source connection.
* \param[in] conn_dst associated destination connection.
* \returns 0 on success, negative on ERROR. */
* \returns 0 on success, -1 on ERROR. */
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst)
@@ -1161,10 +1169,18 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
* IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
* {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
if (mgcp_patch_pt(conn_dst, msg) < 0) {
LOGPENDP(endp, DRTP, LOGL_NOTICE, "unable to patch payload type RTP packet, discarding...\n");
msgb_free(msg);
return -EINVAL;
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
/* FIXME: It is legal that the payload type on the egress connection is
* different from the payload type that has been negotiated on the
* ingress connection. Essentially the codecs are the same so we can
* match them and patch the payload type. However, if we can not find
* the codec pendant (everything ist equal except the PT), we are of
* course unable to patch the payload type. A situation like this
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"can not patch PT because no suitable egress codec was found.\n");
}
}
@@ -1189,69 +1205,73 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
int cont;
int nbytes = 0;
int buflen = msgb_length(msg);
/* Make sure we have a valid RTP header, in cases where no RTP
* header is present, we will generate one. */
gen_rtp_header(msg, rtp_end, rtp_state);
/* Run transcoder */
rc = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error %d during transcoding\n", rc);
msgb_free(msg);
return rc;
}
do {
/* Run transcoder */
cont = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, (char *)msgb_data(msg), &buflen, RTP_BUF_SIZE);
if (cont < 0)
break;
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
msgb_free(msg);
return rc;
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
break;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
break;
}
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
msgb_free(msg);
return rc;
}
}
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
len = msgb_length(msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
(char *)msgb_data(msg), msgb_length(msg));
rc = mgcp_udp_send_msg(rtp_end->rtp, &rtp_end->addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
if (len <= 0)
return len;
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
nbytes += len;
buflen = cont;
} while (buflen > 0);
return nbytes;
} else if (!trunk->omit_rtcp) {
struct osmo_sockaddr rtcp_addr = rtp_end->addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(rtp_end->rtcp_port));
osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"send to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
@@ -1259,54 +1279,19 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtcp_addr.u.sa)
);
len = msgb_length(msg);
rc = mgcp_udp_send_msg(rtp_end->rtcp, &rtcp_addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
(char *)msgb_data(msg), msgb_length(msg));
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
return len;
}
msgb_free(msg);
return 0;
}
/*! determine if there's only a single recipient in endp for data received via conn_src.
* The function returns NULL in case there is no recipient, or in case there are multiple recipients.
* \param endp The MGCP endpoint whose connections to analyze
* \param conn_src The source MGCP connection [which shall not count in results]
* \returns recipient donnection if there is only one; NULL in case there are multiple */
static struct mgcp_conn *rtpbridge_get_only_recipient(struct mgcp_endpoint *endp, struct mgcp_conn *conn_src)
{
struct mgcp_conn *conn_ret = NULL;
struct mgcp_conn *conn_dst;
llist_for_each_entry(conn_dst, &endp->conns, entry) {
if (conn_dst == conn_src)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
if (conn_ret)
return NULL;
conn_ret = conn_dst;
break;
default:
break;
}
}
return conn_ret;
}
/*! Dispatch incoming RTP packet to opposite RTP connection.
* \param[in] msg Message buffer to bridge, coming from source connection.
* msg shall contain "struct osmo_rtp_msg_ctx *" attached in
@@ -1319,10 +1304,8 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
struct mgcp_conn_rtp *conn_src = mc->conn_src;
struct mgcp_conn *conn = conn_src->conn;
struct mgcp_conn *conn_dst;
struct mgcp_endpoint *endp = conn->endp;
struct osmo_sockaddr *from_addr = mc->from_addr;
char ipbuf[INET6_ADDRSTRLEN];
int rc = 0;
/*! NOTE: This callback function implements the endpoint specific
* dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
@@ -1354,56 +1337,36 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
/* If the mode does not allow receiving RTP, we are done. */
switch (conn->mode) {
case MGCP_CONN_RECV_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
break;
default:
return rc;
}
/* All the use cases above are 1:1 where we have one source msgb and we're sending that to one
* destination. msgb ownership had been passed to the respective _*dospatch_rtp() function.
* In the cases below, we actually [can] have multiple recipients, so we copy the original msgb
* for each of the recipients. */
/* If the mode is "confecho", send RTP back to the sender. */
if (conn->mode == MGCP_CONN_CONFECHO) {
struct msgb *msg2 = mgw_msgb_copy_c(conn, msg, "RTP confecho");
if (OSMO_LIKELY(msg2))
rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg2);
}
conn_dst = rtpbridge_get_only_recipient(endp, conn);
if (OSMO_LIKELY(conn_dst)) {
/* we only have a single recipient and cann hence send the original msgb without copying */
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
/* Find a destination connection. */
/* NOTE: This code path runs every time an RTP packet is received. The
* function mgcp_find_dst_conn() we use to determine the detination
* connection will iterate the connection list inside the endpoint.
* Since list iterations are quite costly, we will figure out the
* destination only once and use the optional private data pointer of
* the connection to cache the destination connection pointer. */
if (!conn->priv) {
conn_dst = mgcp_find_dst_conn(conn);
conn->priv = conn_dst;
} else {
/* Dispatch RTP packet to all other connection(s) that send audio. */
llist_for_each_entry(conn_dst, &endp->conns, entry) {
struct msgb *msg2;
if (conn_dst == conn)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
/* we have multiple recipients and must make copies for each recipient */
msg2 = mgw_msgb_copy_c(conn_dst, msg, "RTP Tx copy");
if (OSMO_LIKELY(msg2))
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg2);
break;
default:
break;
}
}
/* as we only sent copies in the previous llist_for_each_entry() loop, we must free the
* original one */
msgb_free(msg);
conn_dst = (struct mgcp_conn *)conn->priv;
}
return rc;
/* There is no destination conn, stop here */
if (!conn_dst) {
LOGPCONN(conn, DRTP, LOGL_DEBUG,
"no connection to forward an incoming RTP packet to\n");
return -1;
}
/* The destination conn is not an RTP connection */
if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
LOGPCONN(conn, DRTP, LOGL_ERROR,
"unable to find suitable destination conn\n");
return -1;
}
/* Dispatch RTP packet to destination RTP connection */
return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
}
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
@@ -1473,7 +1436,7 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
}
/* Handle incoming RTP data from NET */
static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *saddr)
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
{
/* NOTE: This is a generic implementation. RTP data is received. In
* case of loopback the data is just sent back to its origin. All
@@ -1484,34 +1447,49 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
struct mgcp_conn_rtp *conn_src;
struct mgcp_endpoint *endp;
struct osmo_sockaddr addr;
socklen_t slen = sizeof(addr);
char ipbuf[INET6_ADDRSTRLEN];
int ret;
enum rtp_proto proto;
struct osmo_rtp_msg_ctx *mc;
struct msgb *msg;
int rc;
conn_src = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
conn_src = (struct mgcp_conn_rtp *)fd->data;
OSMO_ASSERT(conn_src);
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx");
proto = (iofd == conn_src->end.rtp) ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
if (res <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(-res));
goto out_free;
ret = recvfrom(fd->fd, msgb_data(msg), msg->data_len, 0, (struct sockaddr *)&addr.u.sa, &slen);
if (ret <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
rc = -1;
goto out;
}
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s\n",
msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
msgb_length(msg), osmo_sockaddr_to_str(saddr));
msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
osmo_sockaddr_port(&addr.u.sa));
if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
|| (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
/* Logging happened in the two check_ functions */
goto out_free;
rc = -1;
goto out;
}
if (mgcp_is_rtp_dummy_payload(msg)) {
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
goto out_free;
rc = 0;
goto out;
}
/* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
@@ -1520,7 +1498,7 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
*mc = (struct osmo_rtp_msg_ctx){
.proto = proto,
.conn_src = conn_src,
.from_addr = (struct osmo_sockaddr *) saddr,
.from_addr = &addr,
};
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
mc->proto, mc->conn_src,
@@ -1535,17 +1513,16 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(iofd, &conn_src->tap_in, msg);
forward_data_tap(fd->fd, &conn_src->tap_in, msg);
rx_rtp(msg);
return;
rc = rx_rtp(msg);
out_free:
out:
msgb_free(msg);
return rc;
}
/* Note: This function is able to handle RTP and RTCP. msgb ownership is transferred, so this function or its
* downstream consumers must make sure to [eventually] free the msgb. */
/* Note: This function is able to handle RTP and RTCP */
static int rx_rtp(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
@@ -1558,23 +1535,22 @@ static int rx_rtp(struct msgb *msg)
/* Check if the origin of the RTP packet seems plausible */
if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
goto out_free;
return -1;
/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
if (mc->proto == MGCP_PROTO_RTP
&& conn_src->end.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
if (mc->proto == MGCP_PROTO_RTP &&
mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
* communicated via SDP when the connection was created/modfied. */
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
goto out_free;
return -1;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
goto out_free;
return -1;
}
}
@@ -1583,36 +1559,17 @@ static int rx_rtp(struct msgb *msg)
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
return conn->endp->type->dispatch_rtp_cb(msg);
out_free:
msgb_free(msg);
return -1;
}
static void rtp_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *daddr)
{
/* nothing; osmo_io takes care of msgb_free */
if (res < 0) {
struct mgcp_conn_rtp *conn_rtp = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
int priv_nr = osmo_iofd_get_priv_nr(iofd);
char errbuf[129];
strerror_r(-res, errbuf, sizeof(errbuf));
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
osmo_sockaddr_to_str(daddr), errbuf);
}
}
static const struct osmo_io_ops rtp_ioops = {
.recvfrom_cb = rtp_recvfrom_cb,
.sendto_cb = rtp_sendto_cb,
};
/*! bind RTP port to osmo_fd.
* \param[in] source_addr source (local) address to bind on.
* \param[in] fd associated file descriptor.
* \param[in] port to bind on.
* \param[in] dscp IP DSCP value to use.
* \param[in] prio socket priority to use.
* \returns file descriptor on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio)
* \returns 0 on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio)
{
int rc;
@@ -1620,50 +1577,47 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr
NULL, 0, OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(dscp) |
OSMO_SOCK_F_PRIO(prio));
if (rc < 0) {
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%d).\n",
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
source_addr, port);
return -1;
}
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%d).\n", source_addr, port);
fd->fd = rc;
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
return rc;
return 0;
}
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
int rc, rtp_fd, rtcp_fd;
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
rc = mgcp_create_bind(source_addr, rtp_end->local_port, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
if (mgcp_create_bind(source_addr, &rtp_end->rtp, rtp_end->local_port,
cfg->endp_dscp, cfg->endp_priority) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTP port: %s:%d\n",
source_addr, rtp_end->local_port);
goto cleanup0;
}
rtp_fd = rc;
rc = mgcp_create_bind(source_addr, rtp_end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
if (mgcp_create_bind(source_addr, &rtp_end->rtcp, rtp_end->local_port + 1,
cfg->endp_dscp, cfg->endp_priority) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTCP port: %s:%d\n",
source_addr, rtp_end->local_port + 1);
goto cleanup1;
}
rtcp_fd = rc;
if (osmo_iofd_register(rtp_end->rtp, rtp_fd) < 0) {
if (osmo_fd_register(&rtp_end->rtp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTP port %d\n",
rtp_end->local_port);
goto cleanup2;
}
if (osmo_iofd_register(rtp_end->rtcp, rtcp_fd) != 0) {
if (osmo_fd_register(&rtp_end->rtcp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTCP port %d\n",
rtp_end->local_port + 1);
@@ -1673,11 +1627,13 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
return 0;
cleanup3:
osmo_iofd_unregister(rtp_end->rtp);
osmo_fd_unregister(&rtp_end->rtp);
cleanup2:
close(rtcp_fd);
close(rtp_end->rtcp.fd);
rtp_end->rtcp.fd = -1;
cleanup1:
close(rtp_fd);
close(rtp_end->rtp.fd);
rtp_end->rtp.fd = -1;
cleanup0:
return -1;
}
@@ -1696,8 +1652,7 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
(end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
rtp_port, mgcp_conn_dump(conn->conn));
@@ -1710,18 +1665,8 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
}
end->local_port = rtp_port;
end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtp)
return -EIO;
osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtcp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
}
osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
osmo_fd_setup(&end->rtp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
osmo_fd_setup(&end->rtcp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
}
@@ -1730,13 +1675,15 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
* \param[in] end RTP end */
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
if (end->rtp.fd != -1) {
osmo_fd_unregister(&end->rtp);
close(end->rtp.fd);
end->rtp.fd = -1;
}
if (end->rtcp) {
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
if (end->rtcp.fd != -1) {
osmo_fd_unregister(&end->rtcp);
close(end->rtcp.fd);
end->rtcp.fd = -1;
}
}

View File

@@ -1,7 +1,6 @@
/*
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
* (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All rights not specifically granted under this license are reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,11 +13,9 @@
#include <string.h> /* for memcpy */
#include <stdlib.h> /* for abs */
#include <inttypes.h> /* for PRIu64 */
#include <unistd.h> /* for PRIu64 */
#include <netinet/in.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/talloc.h>
#include <osmocom/netif/osmux.h>
@@ -33,8 +30,8 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
static struct osmo_io_fd *osmux_fd_v4;
static struct osmo_io_fd *osmux_fd_v6;
static struct osmo_fd osmux_fd_v4;
static struct osmo_fd osmux_fd_v6;
static LLIST_HEAD(osmux_handle_list);
@@ -79,31 +76,34 @@ static void rtpconn_osmux_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, int id)
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
{
struct osmux_handle *handle = data;
int rc;
struct osmo_io_fd *iofd;
struct mgcp_trunk *trunk = (struct mgcp_trunk *) osmo_iofd_get_data(osmux_fd_v4);
socklen_t dest_len;
int rc, fd;
struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd_v4.data;
struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
switch (handle->rem_addr.u.sa.sa_family) {
case AF_INET6:
iofd = osmux_fd_v6;
dest_len = sizeof(handle->rem_addr.u.sin6);
fd = osmux_fd_v6.fd;
break;
case AF_INET:
default:
iofd = osmux_fd_v4;
dest_len = sizeof(handle->rem_addr.u.sin);
fd = osmux_fd_v4.fd;
break;
}
rc = osmo_iofd_sendto_msgb(iofd, batch_msg, 0, &handle->rem_addr);
rc = sendto(fd, batch_msg->data, batch_msg->len, 0,
(struct sockaddr *)&handle->rem_addr.u.sa, dest_len);
if (rc < 0) {
char errbuf[129];
strerror_r(-rc, errbuf, sizeof(errbuf));
strerror_r(errno, errbuf, sizeof(errbuf));
LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n",
osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
msgb_free(batch_msg);
} else {
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_PACKETS_TX_CTR));
}
msgb_free(batch_msg);
}
/* Lookup existing OSMUX handle for specified destination address. */
@@ -204,17 +204,17 @@ osmux_handle_find_or_create(const struct mgcp_trunk *trunk, const struct osmo_so
return h->in;
}
/*! send RTP packet through OSMUX connection. Takes ownership of msg.
/*! send RTP packet through OSMUX connection.
* \param[in] conn associated RTP connection
* \param[in] msg msgb containing an RTP AMR packet
* \returns 0 on success, -1 on ERROR */
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
{
int ret;
struct msgb *msg2;
if (!conn->end.output_enabled) {
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
msgb_free(msg);
return -1;
}
@@ -222,19 +222,22 @@ int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
LOGPCONN(conn->conn, DOSMUX, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
conn->osmux.remote_cid);
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
msgb_free(msg);
return -1;
}
/* msg is not owned by us and will be freed by the caller stack upon return: */
msg2 = msgb_copy_c(conn->conn, msg, "osmux-rtp-send");
if (!msg2)
return -1;
/* Osmux implementation works with AMR OA only, make sure we convert to it if needed: */
if (amr_oa_bwe_convert(conn->conn->endp, msg, true) < 0) {
if (amr_oa_bwe_convert(conn->conn->endp, msg2, true) < 0) {
LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
"Error converting to AMR octet-aligned mode\n");
msgb_free(msg);
return -1;
}
while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.remote_cid)) > 0) {
while ((ret = osmux_xfrm_input(conn->osmux.in, msg2, conn->osmux.remote_cid)) > 0) {
/* batch full, build and deliver it */
osmux_xfrm_input_deliver(conn->osmux.in);
}
@@ -242,7 +245,7 @@ int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
} else {
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg) - sizeof(struct rtp_hdr));
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg2) - sizeof(struct rtp_hdr));
}
return 0;
}
@@ -322,7 +325,29 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
};
endp->type->dispatch_rtp_cb(msg);
/* dispatch_rtp_cb() has taken ownership of the msgb */
msgb_free(msg);
}
static struct msgb *osmux_recv(struct osmo_fd *ofd, struct osmo_sockaddr *addr)
{
struct msgb *msg;
socklen_t slen = sizeof(addr->u.sas);
int ret;
msg = msgb_alloc(4096, "OSMUX");
if (!msg) {
LOGP(DOSMUX, LOGL_ERROR, "cannot allocate message\n");
return NULL;
}
ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0, &addr->u.sa, &slen);
if (ret <= 0) {
msgb_free(msg);
LOGP(DOSMUX, LOGL_ERROR, "cannot receive message\n");
return NULL;
}
msgb_put(msg, ret);
return msg;
}
/* To be called every time some AMR data is received on a connection
@@ -420,16 +445,22 @@ out:
}
#define osmux_chunk_length(msg, rem) ((rem) - (msg)->len)
static void osmux_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *rem_addr)
static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
{
struct msgb *msg;
struct osmux_hdr *osmuxh;
struct mgcp_trunk *trunk = osmo_iofd_get_data(iofd);
struct rate_ctr_group *all_rtp_stats = trunk->ratectr.all_osmux_conn_stats;
struct osmo_sockaddr rem_addr;
uint32_t rem;
struct mgcp_trunk *trunk = ofd->data;
struct rate_ctr_group *all_rtp_stats = trunk->ratectr.all_osmux_conn_stats;
char addr_str[64];
msg = osmux_recv(ofd, &rem_addr);
if (!msg)
return -1;
rate_ctr_inc(rate_ctr_group_get_ctr(all_rtp_stats, OSMUX_PACKETS_RX_CTR));
osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), rem_addr);
osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), &rem_addr);
if (trunk->cfg->osmux.usage == OSMUX_USAGE_OFF) {
LOGP(DOSMUX, LOGL_ERROR,
@@ -439,16 +470,14 @@ static void osmux_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg
}
/* Catch legacy dummy message and process them separately: */
if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD) {
osmux_handle_legacy_dummy(trunk, rem_addr, msg);
return;
}
if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD)
return osmux_handle_legacy_dummy(trunk, &rem_addr, msg);
rem = msg->len;
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
struct mgcp_conn_rtp *conn_src;
conn_src = osmux_conn_lookup(trunk, osmuxh->circuit_id,
rem_addr);
&rem_addr);
if (!conn_src) {
LOGP(DOSMUX, LOGL_DEBUG,
"Cannot find a src conn for %s CID=%d\n",
@@ -456,7 +485,7 @@ static void osmux_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg
goto next;
}
if (conn_osmux_event_data_received(conn_src, rem_addr) < 0)
if (conn_osmux_event_data_received(conn_src, &rem_addr) < 0)
goto next;
mgcp_conn_watchdog_kick(conn_src->conn);
@@ -470,94 +499,58 @@ next:
}
out:
msgb_free(msg);
return 0;
}
static void osmux_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *rem_addr)
{
/* nothing; osmo_io takes care of msgb_free */
if (res < 0) {
struct mgcp_trunk *trunk = (struct mgcp_trunk *) osmo_iofd_get_data(iofd);
struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
char errbuf[129];
strerror_r(-res, errbuf, sizeof(errbuf));
LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n", osmo_sockaddr_to_str(rem_addr), errbuf);
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
}
}
static const struct osmo_io_ops osmux_ioops = {
.recvfrom_cb = osmux_recvfrom_cb,
.sendto_cb = osmux_sendto_cb,
};
int osmux_init(struct mgcp_trunk *trunk)
{
int ret, fd;
int ret;
struct mgcp_config *cfg = trunk->cfg;
/* So far we only support running on one trunk: */
OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
osmux_fd_v4 = osmo_iofd_setup(trunk, -1, "osmux_fd_v4", OSMO_IO_FD_MODE_RECVFROM_SENDTO, &osmux_ioops, trunk);
if (!osmux_fd_v4)
goto out;
osmo_iofd_set_alloc_info(osmux_fd_v4, 4096, 0);
osmo_fd_setup(&osmux_fd_v4, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
osmo_fd_setup(&osmux_fd_v6, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
if (cfg->osmux.local_addr_v4) {
ret = mgcp_create_bind(cfg->osmux.local_addr_v4, cfg->osmux.local_port,
ret = mgcp_create_bind(cfg->osmux.local_addr_v4, &osmux_fd_v4, cfg->osmux.local_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
cfg->osmux.local_addr_v4, cfg->osmux.local_port);
goto out_free_v4;
return ret;
}
fd = ret;
ret = osmo_iofd_register(osmux_fd_v4, fd);
ret = osmo_fd_register(&osmux_fd_v4);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", osmo_sock_get_name2(fd));
close(fd);
goto out_free_v4;
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n",
osmo_sock_get_name2(osmux_fd_v4.fd));
return ret;
}
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n", osmo_sock_get_name2(fd));
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n",
osmo_sock_get_name2(osmux_fd_v4.fd));
}
osmux_fd_v6 = osmo_iofd_setup(trunk, -1, "osmux_fd_v6", OSMO_IO_FD_MODE_RECVFROM_SENDTO, &osmux_ioops, trunk);
if (!osmux_fd_v6)
goto out_free_v4;
osmo_iofd_set_alloc_info(osmux_fd_v6, 4096, 0);
if (cfg->osmux.local_addr_v6) {
ret = mgcp_create_bind(cfg->osmux.local_addr_v6, cfg->osmux.local_port,
ret = mgcp_create_bind(cfg->osmux.local_addr_v6, &osmux_fd_v6, cfg->osmux.local_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
cfg->osmux.local_addr_v6, cfg->osmux.local_port);
goto out_free_v6;
return ret;
}
fd = ret;
ret = osmo_iofd_register(osmux_fd_v6, fd);
ret = osmo_fd_register(&osmux_fd_v6);
if (ret < 0) {
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n", osmo_sock_get_name2(fd));
close(fd);
goto out_free_v6;
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n",
osmo_sock_get_name2(osmux_fd_v6.fd));
return ret;
}
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n", osmo_sock_get_name2(fd));
LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n",
osmo_sock_get_name2(osmux_fd_v6.fd));
}
cfg->osmux.initialized = true;
return 0;
out_free_v6:
/* osmo_iofd_free performs unregister + close */
osmo_iofd_free(osmux_fd_v6);
osmux_fd_v6 = NULL;
out_free_v4:
/* osmo_iofd_free performs unregister + close */
osmo_iofd_free(osmux_fd_v4);
osmux_fd_v4 = NULL;
out:
return -1;
}
/*! relase OSXMUX cid, that had been allocated to this connection.
@@ -695,7 +688,7 @@ void conn_osmux_disable(struct mgcp_conn_rtp *conn)
/*! send RTP dummy packet to OSMUX connection port.
* \param[in] conn associated RTP connection
* \returns 0 in case of success, -1 on error */
* \returns bytes sent, -1 on error */
int osmux_send_dummy(struct mgcp_conn_rtp *conn)
{
char ipbuf[INET6_ADDRSTRLEN];
@@ -723,7 +716,7 @@ int osmux_send_dummy(struct mgcp_conn_rtp *conn)
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid);
return mgcp_udp_send(osmux_fd_v4, &conn->end.addr, (char *)osmuxh, buf_len);
return mgcp_udp_send(osmux_fd_v4.fd, &conn->end.addr, (char *)osmuxh, buf_len);
}
/* Keeps track of locally allocated Osmux circuit ID. +7 to round up to 8 bit boundary. */

View File

@@ -86,9 +86,6 @@ struct mgcp_request_data {
/* set to true when the request has been classified as wildcarded */
bool wildcarded;
/* Set to true when the request is targeted at the "null" endpoint */
bool null_endp;
/* contains cause code in case of problems during endp/trunk resolution */
int mgcp_cause;
};
@@ -393,10 +390,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
rq.pdata = &pdata;
rq.wildcarded = mgcp_endp_is_wildcarded(pdata.epname);
if (!rq.wildcarded)
rq.null_endp = mgcp_endp_is_null(pdata.epname);
if (!rq.null_endp)
rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
rq.mgcp_cause = rc;
if (!rq.endp) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_NO_ENDPOINT));
@@ -413,14 +407,14 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
rq.name, pdata.epname);
return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
}
} else if (!rq.null_endp) {
} else {
/* If the endpoint name suggests that the request refers to a specific endpoint, then the
* request cannot be handled and we must stop early. */
LOGP(DLMGCP, LOGL_NOTICE,
"%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
pdata.epname, -rq.mgcp_cause);
return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
} /* else: Handle special "null" endpoint below (with rq.endp=NULL, rq.trunk=NULL) */
}
} else {
osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
rq.trunk = rq.endp->trunk;
@@ -466,11 +460,6 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
{
LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
/* Auditing "null" endpoint is allowed for keepalive purposes. There's no rq->endp nor rq->trunk in this case. */
if (rq->null_endp)
return create_ok_response(rq->pdata->cfg, NULL, 200, "AUEP", rq->pdata->trans);
if (!rq->endp || !mgcp_endp_avail(rq->endp)) {
LOGPENDP(rq->endp, DLMGCP, LOGL_ERROR, "AUEP: selected endpoint not available!\n");
return create_err_response(rq->trunk, NULL, 501, "AUEP", rq->pdata->trans);
@@ -672,8 +661,8 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
case 'a':
/* FIXME: LCO also supports the negotiation of more than one codec.
* (e.g. a:PCMU;G726-32) But this implementation only supports a single
* codec only. Ignoring all but the first codec. */
if (sscanf(lco_id + 1, ":%16[^,;]", codec) == 1) {
* codec only. */
if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
talloc_free(lco->codec);
/* MGCP header is case insensive, and we'll need
codec in uppercase when using it later: */
@@ -772,9 +761,6 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
struct mgcp_request_data *rq, int have_sdp, bool crcx)
{
struct mgcp_endpoint *endp = rq->endp;
struct mgcp_conn *conn_dst;
struct mgcp_conn_rtp *conn_dst_rtp;
int rc;
char *cmd;
@@ -816,15 +802,8 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
goto error;
}
/* Try to find an destination RTP connection that we can include in the codec decision. */
conn_dst = mgcp_find_dst_conn(conn->conn);
if (conn_dst && conn_dst->type == MGCP_CONN_TYPE_RTP)
conn_dst_rtp = &conn_dst->u.rtp;
else
conn_dst_rtp = NULL;
/* Make codec decision */
if (mgcp_codec_decide(conn, conn_dst_rtp) != 0)
if (mgcp_codec_decide(conn) != 0)
goto error;
return 0;
@@ -866,7 +845,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct rate_ctr_group *rate_ctrs;
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
int error_code = 400;
const char *local_options = NULL;
const char *callid = NULL;
@@ -880,14 +859,6 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
if (rq->null_endp) {
/* trunk not available so rate_ctr aren't available either. */
LOGP(DLMGCP, LOGL_ERROR, "CRCX: Not allowed in 'null' endpoint!\n");
return create_err_response(pdata->cfg, NULL, 502, "CRCX", pdata->trans);
}
rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
/* we must have a free ep */
if (!endp) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
@@ -967,7 +938,7 @@ mgcp_header_done:
}
/* Check if we are able to accept the creation of another connection */
if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns) {
if (llist_count(&endp->conns) >= endp->type->max_conns) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"CRCX: endpoint full, max. %i connections allowed!\n",
endp->type->max_conns);
@@ -1076,6 +1047,9 @@ mgcp_header_done:
rc = mgcp_conn_iuup_init(conn);
}
conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
trunk->audio_fmtp_extra);
if (pdata->cfg->force_ptime) {
conn->end.packet_duration_ms = pdata->cfg->force_ptime;
conn->end.force_output_ptime = 1;
@@ -1083,6 +1057,17 @@ mgcp_header_done:
mgcp_rtp_end_config(endp, 0, &conn->end);
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
"CRCX: selected connection mode type requires an opposite end!\n");
error_code = 527;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC));
goto error2;
}
/* Find a local address for conn based on policy and initial SDP remote
information, then find a free port for it */
if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
@@ -1139,7 +1124,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct rate_ctr_group *rate_ctrs;
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
char new_local_addr[INET6_ADDRSTRLEN];
int error_code = 500;
int silent = 0;
@@ -1154,14 +1139,6 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
if (rq->null_endp) {
/* trunk not available so rate_ctr aren't available either. */
LOGP(DLMGCP, LOGL_ERROR, "MDCX: Not allowed in 'null' endpoint!\n");
return create_err_response(pdata->cfg, NULL, 502, "MDCX", pdata->trans);
}
rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
/* Prohibit wildcarded requests */
if (rq->wildcarded) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
@@ -1279,10 +1256,17 @@ mgcp_header_done:
error_code = rc;
goto error3;
}
/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
/* TODO: "codec" probably needs to be moved from endp to conn */
if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0)
rc = mgcp_conn_iuup_init(conn);
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& !mgcp_rtp_end_remote_addr_available(&conn->end)) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: selected connection mode type requires an opposite end!\n");
error_code = 527;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC));
goto error3;
}
if (mgcp_conn_rtp_is_osmux(conn)) {
OSMO_ASSERT(conn->osmux.local_cid_allocated);
@@ -1366,7 +1350,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct rate_ctr_group *rate_ctrs;
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
int error_code = 400;
int silent = 0;
char *line;
@@ -1376,18 +1360,10 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
unsigned int i;
/* NOTE: In this handler we can not take it for granted that the endp
* pointer will be populated, however a trunk is always guaranteed (except for 'null' endp).
*/
* pointer will be populated, however a trunk is always guaranteed. */
LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: deleting connection(s) ...\n");
if (rq->null_endp) {
/* trunk not available so rate_ctr aren't available either. */
LOGP(DLMGCP, LOGL_ERROR, "DLCX: Not allowed in 'null' endpoint!\n");
return create_err_response(pdata->cfg, NULL, 502, "DLCX", pdata->trans);
}
rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
if (endp && !mgcp_endp_avail(endp)) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
@@ -1538,12 +1514,6 @@ static struct msgb *handle_rsip(struct mgcp_request_data *rq)
LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
if (rq->null_endp) {
/* trunk not available so rate_ctr aren't available either. */
LOGP(DLMGCP, LOGL_ERROR, "RSIP: Not allowed in 'null' endpoint!\n");
return create_err_response(rq->pdata->cfg, NULL, 502, "RSIP", rq->pdata->trans);
}
if (rq->pdata->cfg->reset_cb)
rq->pdata->cfg->reset_cb(rq->endp->trunk);
return NULL;
@@ -1569,12 +1539,6 @@ static struct msgb *handle_noti_req(struct mgcp_request_data *rq)
LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
if (rq->null_endp) {
/* trunk not available so rate_ctr aren't available either. */
LOGP(DLMGCP, LOGL_ERROR, "RQNT: Not allowed in 'null' endpoint!\n");
return create_err_response(rq->pdata->cfg, NULL, 502, "RQNT", rq->pdata->trans);
}
for_each_line(line, rq->pdata->save) {
switch (toupper(line[0])) {
case 'S':
@@ -1687,6 +1651,8 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
INIT_LLIST_HEAD(&cfg->trunks);
/* Allocate virtual trunk */

View File

@@ -239,12 +239,13 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
if (delimiter == ';' || delimiter == ',')
str_ptr[strlen(str_ptr) - 1] = '\0';
/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
/* AMR octet aligned parameter */
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
fmtp_param->param.amr_octet_aligned_present = true;
fmtp_param->param.amr_octet_aligned = false;
if (amr_octet_aligned == 1)
fmtp_param->param.amr_octet_aligned = true;
}
param_str = strtok(NULL, " ");
@@ -488,10 +489,34 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
}
/* Add fmtp strings to sdp payload */
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
const char *fmtp_extra)
{
unsigned int i;
int rc;
int fmtp_extra_pt = -1;
char *fmtp_extra_pars = "";
/* When no fmtp parameters ara available but an fmtp extra string
* is configured, just add the fmtp extra string */
if (fmtp_params_len == 0 && fmtp_extra) {
return msgb_printf(sdp, "%s\r\n", fmtp_extra);
}
/* When there is fmtp extra configured we dissect it in order to drop
* in the configured extra parameters at the right place when
* generating the fmtp strings. */
if (fmtp_extra) {
if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
fmtp_extra_pt = -1;
fmtp_extra_pars = strstr(fmtp_extra, " ");
if (!fmtp_extra_pars)
fmtp_extra_pars = "";
else
fmtp_extra_pars++;
}
for (i = 0; i < fmtp_params_len; i++) {
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
@@ -508,6 +533,13 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
return -EINVAL;
}
/* Append extra parameters from fmtp extra */
if (fmtp_params[i].payload_type == fmtp_extra_pt) {
rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
if (rc < 0)
return -EINVAL;
}
rc = msgb_printf(sdp, "\r\n");
if (rc < 0)
return -EINVAL;
@@ -527,6 +559,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
const char *addr)
{
const struct mgcp_rtp_codec *codec;
const char *fmtp_extra;
const char *audio_name;
int payload_type;
struct sdp_fmtp_param fmtp_param;
@@ -542,7 +575,10 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
OSMO_ASSERT(sdp);
OSMO_ASSERT(addr);
codec = conn->end.codec;
/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
endp->trunk->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
&codec, &fmtp_extra,
(struct mgcp_conn_rtp *)conn);
audio_name = codec->audio_name;
payload_type = codec->payload_type;
@@ -584,7 +620,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
fmtp_params[0] = fmtp_param;
fmtp_params_len = 1;
}
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len);
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
if (rc < 0)
goto buffer_too_small;
}

View File

@@ -111,12 +111,17 @@ static int config_write_mgcp(struct vty *vty)
VTY_NEWLINE);
} else
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
if (trunk->audio_fmtp_extra)
vty_out(vty, " sdp audio fmtp-extra %s%s",
trunk->audio_fmtp_extra, VTY_NEWLINE);
vty_out(vty, " %ssdp audio-payload send-ptime%s",
trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
vty_out(vty, " %ssdp audio-payload send-name%s",
trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
vty_out(vty, " number endpoints %u%s",
trunk->v.vty_number_endpoints, VTY_NEWLINE);
vty_out(vty, " %sallow-transcoding%s",
trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
if (strlen(g_cfg->call_agent_addr))
vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
VTY_NEWLINE);
@@ -184,7 +189,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
" Payload Type: %d Rate: %u Channels: %d %s"
" Frame Duration: %u Frame Denominator: %u%s"
" FPP: %d Packet Duration: %u%s"
" Audio-Name: %s Sub-Type: %s%s"
" FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
" Output-Enabled: %d Force-PTIME: %d%s",
tx_packets->current, tx_bytes->current, VTY_NEWLINE,
rx_packets->current, rx_bytes->current, VTY_NEWLINE,
@@ -195,7 +200,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
codec->frame_duration_num, codec->frame_duration_den,
VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
VTY_NEWLINE, codec->audio_name,
VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
codec->subtype_name, VTY_NEWLINE, end->output_enabled,
end->force_output_ptime, VTY_NEWLINE);
if (mgcp_conn_rtp_is_osmux(conn)) {
@@ -508,7 +513,6 @@ DEFUN_DEPRECATED(cfg_mgcp_bind_early,
BIND_STR
"Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
{
vty_out(vty, "%% Deprecated 'bind early (0|1)' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -678,40 +682,53 @@ DEFUN_USRATTR(cfg_mgcp_no_rtp_force_ptime,
return CMD_SUCCESS;
}
DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
cfg_mgcp_sdp_fmtp_extra_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"sdp audio fmtp-extra .NAME",
"Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
"Extra Information\n")
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
char *txt = argv_concat(argv, argc, 0);
if (!txt)
return CMD_WARNING;
osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
talloc_free(txt);
return CMD_SUCCESS;
}
DEFUN_USRATTR(cfg_mgcp_allow_transcoding,
cfg_mgcp_allow_transcoding_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"allow-transcoding", "Allow transcoding\n")
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
trunk->no_audio_transcoding = 0;
return CMD_SUCCESS;
}
DEFUN_USRATTR(cfg_mgcp_no_allow_transcoding,
cfg_mgcp_no_allow_transcoding_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"no allow-transcoding", NO_STR "Allow transcoding\n")
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
trunk->no_audio_transcoding = 1;
return CMD_SUCCESS;
}
#define SDP_STR "SDP File related options\n"
#define AUDIO_STR "Audio payload options\n"
DEFUN_DEPRECATED(cfg_mgcp_sdp_fmtp_extra,
cfg_mgcp_sdp_fmtp_extra_cmd,
"sdp audio fmtp-extra .NAME",
SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
{
vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_mgcp_allow_transcoding,
cfg_mgcp_allow_transcoding_cmd,
"allow-transcoding", "Allow transcoding\n")
{
vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
cfg_mgcp_no_allow_transcoding_cmd,
"no allow-transcoding", NO_STR "Allow transcoding\n")
{
vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
cfg_mgcp_sdp_payload_number_cmd,
"sdp audio-payload number <0-255>",
SDP_STR AUDIO_STR "Number\n" "Payload number\n")
{
vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -725,7 +742,6 @@ DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_name,
"sdp audio-payload name NAME",
SDP_STR AUDIO_STR "Name\n" "Payload name\n")
{
vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -786,7 +802,6 @@ DEFUN_DEPRECATED(cfg_mgcp_loop,
"loop (0|1)",
"Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
{
vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1051,17 +1066,30 @@ static int config_write_trunk(struct vty *vty)
VTY_NEWLINE);
} else
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
if (trunk->audio_fmtp_extra)
vty_out(vty, " sdp audio fmtp-extra %s%s",
trunk->audio_fmtp_extra, VTY_NEWLINE);
vty_out(vty, " %sallow-transcoding%s",
trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_trunk_sdp_fmtp_extra,
DEFUN_USRATTR(cfg_trunk_sdp_fmtp_extra,
cfg_trunk_sdp_fmtp_extra_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"sdp audio fmtp-extra .NAME",
SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
"Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
"Extra Information\n")
{
vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
struct mgcp_trunk *trunk = vty->index;
char *txt = argv_concat(argv, argc, 0);
if (!txt)
return CMD_WARNING;
osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
talloc_free(txt);
return CMD_SUCCESS;
}
@@ -1070,7 +1098,6 @@ DEFUN_DEPRECATED(cfg_trunk_payload_number,
"sdp audio-payload number <0-255>",
SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
{
vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1083,7 +1110,6 @@ DEFUN_DEPRECATED(cfg_trunk_payload_name,
"sdp audio-payload name NAME",
SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
{
vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1096,7 +1122,6 @@ DEFUN_DEPRECATED(cfg_trunk_loop,
"loop (0|1)",
"Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
{
vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1294,19 +1319,23 @@ DEFUN_ATTR(cfg_trunk_no_rtp_keepalive,
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_trunk_allow_transcoding,
cfg_trunk_allow_transcoding_cmd,
"allow-transcoding", "Allow transcoding\n")
DEFUN_USRATTR(cfg_trunk_allow_transcoding,
cfg_trunk_allow_transcoding_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"allow-transcoding", "Allow transcoding\n")
{
vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
struct mgcp_trunk *trunk = vty->index;
trunk->no_audio_transcoding = 0;
return CMD_SUCCESS;
}
DEFUN_DEPRECATED(cfg_trunk_no_allow_transcoding,
cfg_trunk_no_allow_transcoding_cmd,
"no allow-transcoding", NO_STR "Allow transcoding\n")
DEFUN_USRATTR(cfg_trunk_no_allow_transcoding,
cfg_trunk_no_allow_transcoding_cmd,
X(MGW_CMD_ATTR_NEWCONN),
"no allow-transcoding", NO_STR "Allow transcoding\n")
{
vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
struct mgcp_trunk *trunk = vty->index;
trunk->no_audio_transcoding = 1;
return CMD_SUCCESS;
}

View File

@@ -280,31 +280,6 @@ int mgcp_vty_go_parent(struct vty *vty)
return vty->node;
}
static void signal_handler(int signum)
{
fprintf(stdout, "signal %u received\n", signum);
switch (signum) {
case SIGABRT:
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_mgw_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_mgw_ctx, stderr);
break;
default:
break;
}
}
static struct vty_app_info vty_info = {
.name = "OsmoMGW",
@@ -353,8 +328,6 @@ int main(int argc, char **argv)
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
osmo_init_ignore_signals();
osmo_init_logging2(tall_mgw_ctx, &log_info);
libosmo_abis_init(tall_mgw_ctx);
@@ -387,7 +360,8 @@ int main(int argc, char **argv)
return rc;
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_default(tall_mgw_ctx, NULL, OSMO_VTY_PORT_MGW);
rc = telnet_init_dynif(tall_mgw_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
if (rc < 0)
return rc;

View File

@@ -34,11 +34,11 @@ DISTCLEANFILES = \
$(NULL)
if ENABLE_EXT_TESTS
python-tests: $(top_builddir)/src/osmo-mgw/osmo-mgw
python-tests: $(BUILT_SOURCES)
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
else
python-tests:
python-tests: $(BUILT_SOURCES)
echo "Not running python-based tests (determined at configure-time)"
endif

View File

@@ -18,7 +18,6 @@ AM_CFLAGS = \
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
-no-install \
$(NULL)
EXTRA_DIST = \
@@ -45,6 +44,3 @@ mgcp_test_LDADD = \
$(LIBOSMONETIF_LIBS) \
-lm \
$(NULL)
update_exp:
$(builddir)/mgcp_test >$(srcdir)/mgcp_test.ok

View File

@@ -77,8 +77,6 @@ static void test_strline(void)
#define AUEP1_RET "500 158663169 FAIL\r\n"
#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
#define AUEP2_RET "500 18983213 FAIL\r\n"
#define AUEP_NULL "AUEP 18983215 null@mgw MGCP 1.0\r\n"
#define AUEP_NULL_RET "200 18983215 OK\r\n"
#define EMPTY "\r\n"
#define EMPTY_RET NULL
#define SHORT "CRCX \r\n"
@@ -103,7 +101,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
@@ -115,7 +113,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
@@ -127,49 +125,41 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=fmtp:126 0/1/2\r\n" \
"a=ptime:40\r\n"
#define MDCX4_ADDR0000 \
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_ADDR0000_RET \
"200 18983216 OK\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"527 18983216 FAIL\r\n"
#define MDCX4 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -181,7 +171,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -193,87 +183,87 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 112\r\n" \
"a=rtpmap:112 AMR\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT1 \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: SENDRECV\r\n" \
"M: SENDRECV\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT2 \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT3 \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
/* Test different upper/lower case in options */
#define MDCX4_PT4 \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"m: sendrecv\r\n" \
"m: sendrecv\r" \
"c: 2\r\n" \
"i: %s\r\n" \
"l: A:amr, NT:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_SO \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
@@ -284,12 +274,6 @@ static void test_strline(void)
#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
#define MDCX_NULL \
"MDCX 9 null@mgw MGCP 1.0\r\n" \
"I: %s\n"
#define MDCX_NULL_RET "502 9 FAIL\r\n"
#define SHORT2 "CRCX 1"
#define SHORT2_RET "510 000000 FAIL\r\n"
#define SHORT3 "CRCX 1 1@mgw"
@@ -306,7 +290,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET \
"200 2 OK\r\n" \
@@ -319,7 +303,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
@@ -331,7 +315,7 @@ static void test_strline(void)
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
@@ -344,17 +328,18 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=fmtp:126 0/1/2\r\n" \
"a=ptime:40\r\n"
#define CRCX_ZYN \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"C: 2\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n"
"\n" \
"v=0\r" \
"c=IN IP4 123.12.12.123\r" \
"m=audio 5904 RTP/AVP 97\r" \
"a=rtpmap:97 GSM-EFR/8000\r"
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
@@ -380,7 +365,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_X_OSMO_IGN_RET \
"200 2 OK\r\n" \
@@ -393,95 +378,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16010 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0 \
"CRCX 3 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_RET \
"200 3 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16014 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP_RET \
"200 4 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16016 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX in m=sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX using sendrecv mode in the SDP part */
#define CRCX_PORT_0_IUFP_SENDRECV2 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"a=sendrecv\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX entirely omitting a mode, i.e. implcit sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV3 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
@@ -495,13 +392,6 @@ static void test_strline(void)
#define DLCX_RET_OSMUX DLCX_RET \
"X-Osmo-CP: EC TI=0, TO=0\r\n"
#define DLCX_NULL \
"DLCX 8 null@mgw MGCP 1.0\r\n" \
"I: %s\r\n" \
"C: 2\r\n"
#define DLCX_NULL_RET "502 8 FAIL\r\n"
#define RQNT \
"RQNT 186908780 1@mgw MGCP 1.0\r\n" \
"X: B244F267488\r\n" \
@@ -515,13 +405,6 @@ static void test_strline(void)
#define RQNT1_RET "200 186908780 OK\r\n"
#define RQNT2_RET "200 186908781 OK\r\n"
#define RQNT_NULL \
"RQNT 186908782 null@mgw MGCP 1.0\r\n" \
"X: B244F267488\r\n" \
"S: D/9\r\n"
#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
#define PTYPE_IGNORE 0 /* == default initializer */
#define PTYPE_NONE 128
#define PTYPE_NYI PTYPE_NONE
@@ -538,7 +421,7 @@ static void test_strline(void)
"m=audio 5904 RTP/AVP 18 97\r\n" \
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
@@ -553,7 +436,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
@@ -568,7 +451,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
@@ -583,7 +466,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
@@ -662,25 +545,12 @@ static void test_strline(void)
"m=audio 16008 RTP/AVP 0\r\n" \
"a=ptime:20\r\n"
#define CRCX_NULL \
"CRCX 2 null@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_NULL_RET "502 2 FAIL\r\n"
struct mgcp_test {
const char *name;
const char *req;
const char *exp_resp;
int ptype;
const char *extra_fmtp;
};
static const struct mgcp_test tests[] = {
@@ -708,23 +578,14 @@ static const struct mgcp_test tests[] = {
{"RQNT1", RQNT, RQNT1_RET},
{"RQNT2", RQNT2, RQNT2_RET},
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
{"CRCX", CRCX, CRCX_FMTP_RET, 97},
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
{"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
"a=fmtp:126 0/1/2"},
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
{"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
{"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
{"CRCX_PORT_0", CRCX_PORT_0, CRCX_PORT_0_RET, 97},
{"CRCX_PORT_0_IUFP", CRCX_PORT_0_IUFP, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV", CRCX_PORT_0_IUFP_SENDRECV, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV2", CRCX_PORT_0_IUFP_SENDRECV2, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV3", CRCX_PORT_0_IUFP_SENDRECV3, CRCX_PORT_0_IUFP_RET, 96},
};
static const struct mgcp_test retransmit[] = {
@@ -755,13 +616,12 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
static int dummy_packets = 0;
/* override and forward */
int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
uint32_t dest_host =
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
const uint8_t *buf = msgb_data(msg);
size_t len = msgb_length(msg);
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
if (len == sizeof(rtp_dummy_payload)
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
@@ -775,8 +635,6 @@ int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags,
OSMO_ASSERT(dest_host);
OSMO_ASSERT(dest_port);
msgb_free(msg);
return len;
}
@@ -932,6 +790,9 @@ static void test_messages(void)
dummy_packets = 0;
osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
t->extra_fmtp);
inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
@@ -1208,9 +1069,7 @@ static void test_packet_loss_calc(void)
_conn =
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
state = &conn->state;
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
@@ -1608,6 +1467,7 @@ static void test_multilple_codec(void)
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
last_endpoint[0] = '\0';
inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
trunk->no_audio_transcoding = 1;
resp = mgcp_handle_message(cfg, inp);
OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
sizeof(conn_id)) == 0);
@@ -1651,6 +1511,7 @@ static void test_multilple_codec(void)
last_endpoint[0] = '\0';
inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
trunk->no_audio_transcoding = 0;
resp = mgcp_handle_message(cfg, inp);
OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
sizeof(conn_id)) == 0);
@@ -1908,25 +1769,26 @@ static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
.amr_octet_aligned_present = false,
};
struct testcase_mgcp_codec_decide_codec {
struct testcase_mgcp_codec_pt_translate_codec {
int payload_type;
const char *audio_name;
const struct mgcp_codec_param *param;
int expect_rc;
};
struct testcase_mgcp_codec_decide_expect {
struct testcase_mgcp_codec_pt_translate_expect {
bool end;
int payload_type_map[2];
};
struct testcase_mgcp_codec_decide {
struct testcase_mgcp_codec_pt_translate {
const char *descr;
/* two conns on an endpoint, each with N configured codecs */
struct testcase_mgcp_codec_decide_codec codecs[2][10];
struct testcase_mgcp_codec_decide_expect expect[2];
struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
struct testcase_mgcp_codec_pt_translate_expect expect[32];
};
static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
{
.descr = "same order, but differing payload type numbers",
.codecs = {
@@ -1943,7 +1805,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
.expect = {
{ .payload_type_map = {112, 96}, },
{ .payload_type_map = {112, 96}, },
{ .payload_type_map = {0, 0}, },
{ .payload_type_map = {111, 97} },
{ .payload_type_map = {123, -EINVAL} },
{ .end = true },
},
},
{
@@ -1961,8 +1826,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
},
.expect = {
{ .payload_type_map = {112, 96}, },
{ .payload_type_map = {0, 0}, },
{ .payload_type_map = {111, 97}, },
{ .payload_type_map = {111, 97} },
{ .payload_type_map = {123, -EINVAL} },
{ .end = true },
},
},
{
@@ -1980,8 +1848,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
},
.expect = {
{ .payload_type_map = {0, 0}, },
{ .payload_type_map = {96, 97}, },
{ .payload_type_map = {97, 96}, },
{ .payload_type_map = {0, 0}, },
{ .end = true },
},
},
{
@@ -1997,8 +1867,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
},
.expect = {
{ .payload_type_map = {-EINVAL, -EINVAL}, },
{ .payload_type_map = {-EINVAL, 96}, },
{ .payload_type_map = {112, -EINVAL}, },
{ .payload_type_map = {0, -EINVAL}, },
{ .payload_type_map = {111, -EINVAL} },
{ .end = true },
},
},
{
@@ -2015,60 +1887,28 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
.expect = {
{ .payload_type_map = {112, -EINVAL}, },
{ .payload_type_map = {-EINVAL, -EINVAL}, },
{ .payload_type_map = {0, -EINVAL}, },
{ .payload_type_map = {111, -EINVAL} },
{ .end = true },
},
},
{
.descr = "test AMR with differing octet-aligned settings (both <-> both)",
.codecs = {
{
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
},
{
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
},
},
.expect = {
{ .payload_type_map = {111, 121}, },
{ .payload_type_map = {112, 122} },
},
},
{
.descr = "test AMR with differing octet-aligned settings (oa <-> both)",
.descr = "test AMR with differing octet-aligned settings",
.codecs = {
{
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
},
{
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
},
},
.expect = {
{ .payload_type_map = {111, 121}, },
{ .payload_type_map = {111, 121}, },
{ .payload_type_map = {111, 122}, },
{ .end = true },
},
},
{
.descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
.codecs = {
{
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
},
{
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
},
},
.expect = {
{ .payload_type_map = {112, 122}, },
{ .payload_type_map = {112, 122}, },
},
},
{
.descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
.descr = "test AMR with missing octet-aligned settings (defaults to 0)",
.codecs = {
{
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
@@ -2079,54 +1919,22 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
.expect = {
{ .payload_type_map = {111, 122}, },
{ .payload_type_map = {111, 122}, },
{ .end = true },
},
},
{
.descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
.descr = "test AMR with NULL param (defaults to 0)",
.codecs = {
{
{ 111, "AMR/8000", &amr_param_octet_aligned_false, },
},
{
{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
},
},
.expect = {
{ .payload_type_map = {111, 122}, },
{ .payload_type_map = {111, 122}, },
},
},
{
.descr = "test AMR with NULL param (oa <-> null)",
.codecs = {
{
{ 112, "AMR/8000", &amr_param_octet_aligned_true, },
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
},
{
{ 122, "AMR/8000", NULL, },
},
},
.expect = {
/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
{ .payload_type_map = {112, 122} },
{ .payload_type_map = {112, 122}, },
},
},
{
.descr = "test AMR with NULL param (bwe <-> null)",
.codecs = {
{
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
},
{
{ 122, "AMR/8000", NULL, },
},
},
.expect = {
/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
{ .payload_type_map = {112, 122} },
{ .payload_type_map = {112, 122}, },
{ .payload_type_map = {111, 122}, },
{ .end = true },
},
},
{
@@ -2144,8 +1952,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
},
.expect = {
{ .payload_type_map = {112, 96}, },
{ .payload_type_map = {0, 0}, },
{ .payload_type_map = {111, 97}, },
{ .payload_type_map = {111, 97} },
{ .payload_type_map = {123, -EINVAL} },
{ .end = true },
},
},
{
@@ -2163,8 +1974,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
},
.expect = {
{ .payload_type_map = {112, 96}, },
{ .payload_type_map = {0, 0}, },
{ .payload_type_map = {111, 97}, },
{ .payload_type_map = {111, 97} },
{ .payload_type_map = {123, -EINVAL} },
{ .end = true },
},
},
{
@@ -2182,98 +1996,45 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
},
.expect = {
{ .payload_type_map = {111, 121}, },
{ .payload_type_map = {111, 121} },
{ .payload_type_map = {112, -EINVAL} },
{ .payload_type_map = {113, -EINVAL} },
{ .end = true },
},
},
};
static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
const struct testcase_mgcp_codec_decide_expect *expect)
{
bool ok = true;
int payload_type_conn_src;
int payload_type_conn_dst;
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
if (expect->payload_type_map[index_conn_src] == -EINVAL
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
printf(" codec decision failed (expected)!\n");
else {
printf(" ERROR: codec decision failed!\n");
ok = false;
}
} else {
printf(" Codec decision result:\n");
if (conn[index_conn_src].end.codec) {
payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
} else {
payload_type_conn_src = -EINVAL;
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
}
if (conn[index_conn_dst].end.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
payload_type_conn_dst);
} else {
payload_type_conn_dst = -EINVAL;
printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
}
if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
ok = false;
}
if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
index_conn_dst, expect->payload_type_map[index_conn_dst],
payload_type_conn_dst);
ok = false;
}
}
return ok;
}
static void test_mgcp_codec_decide(void)
static void test_mgcp_codec_pt_translate(void)
{
int i;
bool ok_all = true;
printf("\nTesting mgcp_codec_find_convertible()\n");
bool ok = true;
printf("\nTesting mgcp_codec_pt_translate()\n");
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
struct mgcp_conn_rtp conn[2] = { };
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
struct mgcp_conn_rtp conn[2] = {};
int rc;
int conn_i;
int c;
bool ok = true;
printf("#%d: %s\n", i, t->descr);
/* Build testvector (add codecs to conn, set properties etc... */
for (conn_i = 0; conn_i < 2; conn_i++) {
printf(" - add codecs on conn%d:\n", conn_i);
for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
if (!codec->audio_name)
break;
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
codec->param);
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
codec->param ?
(codec->param->amr_octet_aligned_present ?
(codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
: " octet-aligned=unset")
: "", rc);
(codec->param->amr_octet_aligned_present?
(codec->param->amr_octet_aligned ?
" octet-aligned=1" : " octet-aligned=0")
: " octet-aligned=unset")
: "",
rc);
if (rc != codec->expect_rc) {
printf(" ERROR: expected rc=%d\n", codec->expect_rc);
ok = false;
@@ -2283,23 +2044,39 @@ static void test_mgcp_codec_decide(void)
printf(" (none)\n");
}
/* Run codec decision and check expectation */
if (!codec_decision(conn, 0, 1, &t->expect[0]))
ok = false;
for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
int result;
if (!codec_decision(conn, 1, 0, &t->expect[1]))
ok = false;
if (expect->end)
break;
if (ok)
printf(" ===> SUCCESS: codec decision as expected!\n");
else
printf(" ===> FAIL: unexpected codec decision!\n");
result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
expect->payload_type_map[0], result);
if (result != expect->payload_type_map[1]) {
printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
ok = false;
}
if (!ok)
ok_all = false;
/* If the expected result is an error, don't do reverse map test */
if (expect->payload_type_map[1] < 0)
continue;
result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
expect->payload_type_map[1], result);
if (result != expect->payload_type_map[0]) {
printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
ok = false;
}
}
for (conn_i = 0; conn_i < 2; conn_i++)
mgcp_codec_reset_all(&conn[conn_i]);
}
OSMO_ASSERT(ok_all);
OSMO_ASSERT(ok);
}
void test_conn_id_matching(void)
@@ -2456,7 +2233,7 @@ int main(int argc, char **argv)
test_osmux_cid();
test_get_lco_identifier();
test_check_local_cx_options(ctx);
test_mgcp_codec_decide();
test_mgcp_codec_pt_translate();
test_conn_id_matching();
test_e1_trunk_nr_from_epname();
test_mgcp_is_rtp_dummy_payload();

View File

@@ -73,7 +73,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
a=ptime:40
---------8<---------
checking response:
@@ -101,42 +101,40 @@ Testing MDCX4_ADDR000
creating message from statically defined input:
---------8<---------
MDCX 18983216 1@mgw MGCP 1.0
M: sendrecv
C: 2
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 0.0.0.0
c=IN IP4 0.0.0.0
t=0 0
m=audio 4441 RTP/AVP 99
a=ptime:20
a=rtpmap:99 AMR/8000
a=ptime:40
---------8<---------
using message with patched conn_id for comparison
checking response:
using message as statically defined for comparison
(response contains a connection id)
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX4
creating message from statically defined input:
---------8<---------
M: sendrecv
C: 2
MDCX 18983217 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
a=ptime:20
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -150,18 +148,17 @@ Testing MDCX4_PT1
================================================
Testing MDCX4_PT1
creating message from statically defined input:
M: SENDRECV
C: 2
---------8<---------
MDCX 18983218 1@mgw MGCP 1.0
M: SENDRECV
C: 2
I: %s
L: p:20-40, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
a=ptime:20
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -175,18 +172,17 @@ Testing MDCX4_PT2
================================================
Testing MDCX4_PT2
M: sendrecv
C: 2
creating message from statically defined input:
---------8<---------
MDCX 18983219 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20-20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
a=ptime:20
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
@@ -200,18 +196,17 @@ Testing MDCX4_PT3
Dummy packets: 2
================================================
M: sendrecv
C: 2
Testing MDCX4_PT3
creating message from statically defined input:
---------8<---------
MDCX 18983220 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: a:AMR, nt:IN
v=0
a=ptime:20
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
@@ -225,18 +220,17 @@ Testing MDCX4_PT4
(response contains a connection id)
Dummy packets: 2
m: sendrecv
c: 2
================================================
Testing MDCX4_PT4
creating message from statically defined input:
---------8<---------
MDCX 18983221 1@mgw MGCP 1.0
m: sendrecv
c: 2
i: %s
l: A:amr, NT:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
@@ -250,18 +244,17 @@ Testing MDCX4_SO
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
M: sendonly
C: 2
================================================
Testing MDCX4_SO
creating message from statically defined input:
---------8<---------
MDCX 18983222 1@mgw MGCP 1.0
M: sendonly
C: 2
I: %s
L: p:20, a:AMR, nt:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
@@ -274,8 +267,7 @@ Testing MDCX4_RO
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
M: recvonly
C: 2
(response contains a connection id)
================================================
Testing MDCX4_RO
@@ -304,15 +296,9 @@ Response matches our expectations.
---------8<---------
checking response:
CRCX 2 1@mgw MGCP 1.0
M: recvonly
C: 2
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX_ZYN
@@ -428,7 +414,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing CRCX
creating message from statically defined input:
---------8<---------
@@ -493,7 +479,7 @@ v=0
(response contains a connection id)
================================================
a=ptime:20
Testing CRCX
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
@@ -539,184 +525,6 @@ Response matches our expectations.
L: p:20
v=0
================================================
Testing AUEP_NULL
creating message from statically defined input:
---------8<---------
AUEP 18983215 null@mgw MGCP 1.0
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX_NULL
creating message from statically defined input:
---------8<---------
CRCX 2 null@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX_NULL
creating message from statically defined input:
---------8<---------
MDCX 9 null@mgw MGCP 1.0
I: %s
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing DLCX_NULL
creating message from statically defined input:
---------8<---------
DLCX 8 null@mgw MGCP 1.0
I: %s
C: 2
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing RQNT_NULL
creating message from statically defined input:
---------8<---------
RQNT 186908782 null@mgw MGCP 1.0
X: B244F267488
S: D/9
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX_PORT_0
creating message from statically defined input:
---------8<---------
CRCX 3 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
M: sendrecv
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV2
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
a=sendrecv
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV3
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 111
a=rtpmap:111 AMR/8000/1
@@ -730,7 +538,7 @@ v=0
(response contains a connection id)
Dummy packets: 2
a=ptime:20
================================================
Testing CRCX
creating message from statically defined input:
---------8<---------
@@ -748,7 +556,7 @@ v=0
---------8<---------
checking response:
using message with patched conn_id for comparison
a=ptime:20
Response matches our expectations.
Re-transmitting CRCX
creating message from statically defined input:
---------8<---------
@@ -860,7 +668,7 @@ v=0
---------8<---------
checking response:
using message as statically defined for comparison
a=ptime:20
Response matches our expectations.
Testing packet loss calculation.
creating message from statically defined input:
---------8<---------
@@ -1314,7 +1122,7 @@ c=IN IP4 123.12.12.123
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 5, Transit = -163760
Testing multiple payload types
a=ptime:20
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
M: recvonly
@@ -1331,7 +1139,7 @@ m=audio 5904 RTP/AVP 18 97 101
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 2@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1348,7 +1156,7 @@ m=audio 5904 RTP/AVP
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 3@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1365,7 +1173,7 @@ m=audio 5904 RTP/AVP 18
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 4@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1447,7 +1255,7 @@ v=0
a=recvonly
---------8<---------
a=ptime:20
Testing no sequence flow on initial packet
Testing no rtpmap name
creating message from statically defined input:
---------8<---------
@@ -1468,7 +1276,7 @@ p:10, a:PCMU -> p:10, a:PCMU
Response matches our expectations.
Testing get_lco_identifier()
p:10, a:PCMU -> p:10, a:PCMU
Testing mgcp_codec_find_convertible()
p:10, a:PCMU -> p:10, a:PCMU
'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
'10,a:PCMU' -> 'a:PCMU'
@@ -1478,15 +1286,13 @@ Testing mgcp_codec_find_convertible()
', a:PCMU' -> 'a:PCMU'
' a:PCMU' -> 'a:PCMU'
'' -> '(null)'
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:112
conn[1]: codec:AMR, pt:96
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:96
conn[0]: codec:AMR, pt:112
===> SUCCESS: codec decision as expected!
p10, aPCMU -> (null)
'10,a :PCMU' -> '(null)'
Testing mgcp_codec_pt_translate()
#0: same order, but differing payload type numbers
- add codecs on conn0:
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
1: 0 PCMU/8000/1 -> rc=0
2: 111 GSM-HR-08/8000/1 -> rc=0
- add codecs on conn1:
@@ -1496,15 +1302,13 @@ Testing mgcp_codec_find_convertible()
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:PCMU, pt:0
conn[1]: codec:PCMU, pt:0
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:GSM-HR-08, pt:97
conn[0]: codec:GSM-HR-08, pt:111
===> SUCCESS: codec decision as expected!
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
#1: different order and different payload type numbers
- add codecs on conn0:
0: 0 PCMU/8000/1 -> rc=0
1: 111 GSM-HR-08/8000/1 -> rc=0
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
- add codecs on conn1:
@@ -1514,15 +1318,12 @@ Testing mgcp_codec_find_convertible()
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:PCMU, pt:0
conn[1]: codec:PCMU, pt:0
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:GSM-HR-08, pt:97
conn[0]: codec:GSM-HR-08, pt:96
===> SUCCESS: codec decision as expected!
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
#2: both sides have the same payload_type numbers assigned to differing codecs
- add codecs on conn0:
0: 0 PCMU/8000/1 -> rc=0
1: 96 GSM-HR-08/8000/1 -> rc=0
2: 97 AMR/8000/1 octet-aligned=1 -> rc=0
@@ -1530,13 +1331,9 @@ Testing mgcp_codec_find_convertible()
0: 97 GSM-HR-08/8000/1 -> rc=0
1: 0 PCMU/8000/1 -> rc=0
2: 96 AMR/8000/1 octet-aligned=1 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
codec decision failed (expected)!
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:96
conn[0]: codec:none, pt:none
===> SUCCESS: codec decision as expected!
- mgcp_codec_pt_translate(conn0, conn1, 96) -> 97
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
- mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
@@ -1544,116 +1341,31 @@ Testing mgcp_codec_find_convertible()
- add codecs on conn0:
(none)
- add codecs on conn1:
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:112
conn[1]: codec:none, pt:none
- mgcp_codec_decide(&conn[1], &conn[0]):
codec decision failed (expected)!
===> SUCCESS: codec decision as expected!
#5: test AMR with differing octet-aligned settings (both <-> both)
- add codecs on conn0:
0: 111 AMR/8000 octet-aligned=1 -> rc=0
1: 112 AMR/8000 octet-aligned=0 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 octet-aligned=0 -> rc=0
1: 121 AMR/8000 octet-aligned=1 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:111
conn[1]: codec:AMR, pt:121
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:112
===> SUCCESS: codec decision as expected!
#6: test AMR with differing octet-aligned settings (oa <-> both)
0: 96 AMR/8000/1 octet-aligned=1 -> rc=0
1: 0 PCMU/8000/1 -> rc=0
2: 97 GSM-HR-08/8000/1 -> rc=0
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
#4: conn1 has no codecs
- add codecs on conn0:
1: 121 AMR/8000 octet-aligned=1 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:111
conn[1]: codec:AMR, pt:121
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:121
conn[0]: codec:AMR, pt:111
===> SUCCESS: codec decision as expected!
#7: test AMR with differing octet-aligned settings (bwe <-> both)
- add codecs on conn0:
0: 112 AMR/8000 octet-aligned=0 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 octet-aligned=0 -> rc=0
1: 121 AMR/8000 octet-aligned=1 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:112
conn[1]: codec:AMR, pt:122
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:112
===> SUCCESS: codec decision as expected!
#8: test AMR with missing octet-aligned settings (oa <-> unset)
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
1: 0 PCMU/8000/1 -> rc=0
2: 111 GSM-HR-08/8000/1 -> rc=0
- add codecs on conn1:
(none)
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:111
conn[1]: codec:AMR, pt:122
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:111
===> SUCCESS: codec decision as expected!
#9: test AMR with missing octet-aligned settings (bwe <-> unset)
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
#5: test AMR with differing octet-aligned settings
- add codecs on conn0:
0: 111 AMR/8000 octet-aligned=1 -> rc=0
0: 111 AMR/8000 octet-aligned=0 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 octet-aligned=unset -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:111
conn[1]: codec:AMR, pt:122
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:111
===> SUCCESS: codec decision as expected!
#10: test AMR with NULL param (oa <-> null)
- add codecs on conn0:
0: 112 AMR/8000 octet-aligned=1 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 octet-aligned=0 -> rc=0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:112
conn[1]: codec:AMR, pt:122
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:112
===> SUCCESS: codec decision as expected!
#11: test AMR with NULL param (bwe <-> null)
- add codecs on conn0:
0: 112 AMR/8000 octet-aligned=0 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:AMR, pt:112
conn[1]: codec:AMR, pt:122
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:AMR, pt:122
conn[0]: codec:AMR, pt:112
===> SUCCESS: codec decision as expected!
#12: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
#6: test AMR with missing octet-aligned settings (defaults to 0)
- add codecs on conn0:
0: 111 AMR/8000 octet-aligned=1 -> rc=0
- add codecs on conn1:
0: 122 AMR/8000 octet-aligned=unset -> rc=0
@@ -1662,16 +1374,14 @@ Testing mgcp_codec_find_convertible()
#7: test AMR with NULL param (defaults to 0)
- add codecs on conn0:
0: 111 AMR/8000 octet-aligned=1 -> rc=0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:PCMU, pt:0
conn[1]: codec:PCMU, pt:0
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:GSM-HR-08, pt:97
conn[0]: codec:GSM-HR-08, pt:111
===> SUCCESS: codec decision as expected!
#13: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
- add codecs on conn1:
0: 122 AMR/8000 -> rc=0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
- add codecs on conn0:
0: 0 PCMU/8000/1 -> rc=0
1: 111 GSM-HR-08/8000/1 -> rc=0
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
- add codecs on conn1:
0: 97 GSM-HR-08/8000 -> rc=0
@@ -1680,16 +1390,14 @@ Testing mgcp_codec_find_convertible()
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:PCMU, pt:0
conn[1]: codec:PCMU, pt:0
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:GSM-HR-08, pt:97
conn[0]: codec:GSM-HR-08, pt:111
===> SUCCESS: codec decision as expected!
#14: test whether channel number matching is waterproof
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
- add codecs on conn0:
0: 0 PCMU/8000/1 -> rc=0
1: 111 GSM-HR-08/8000/1 -> rc=0
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
- add codecs on conn1:
0: 97 GSM-HR-08 -> rc=0
@@ -1697,15 +1405,10 @@ Testing mgcp_codec_find_convertible()
2: 96 AMR octet-aligned=1 -> rc=0
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
- mgcp_codec_decide(&conn[0], &conn[1]):
Codec decision result:
conn[0]: codec:GSM-HR-08, pt:111
conn[1]: codec:GSM-HR-08, pt:121
- mgcp_codec_decide(&conn[1], &conn[0]):
Codec decision result:
conn[1]: codec:GSM-HR-08, pt:121
conn[0]: codec:GSM-HR-08, pt:111
===> SUCCESS: codec decision as expected!
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
#10: test whether channel number matching is waterproof
- add codecs on conn0:

View File

@@ -15,7 +15,6 @@ AM_CFLAGS = \
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
-no-install \
$(NULL)
EXTRA_DIST = \

View File

@@ -73,7 +73,7 @@ static struct msgb *from_str(const char *str)
return msg;
}
static struct mgcp_client_conf *conf;
static struct mgcp_client_conf conf;
struct mgcp_client *mgcp = NULL;
static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
@@ -107,6 +107,9 @@ void test_response_cb(struct mgcp_response *response, void *priv)
printf(" audio_port = %u\n", response->audio_port);
printf(" audio_ip = %s\n", response->audio_ip);
printf(" ptime = %u\n", response->ptime);
printf(" codecs_len = %u\n", response->codecs_len);
for(i=0;i<response->codecs_len;i++)
printf(" codecs[%u] = %u\n", i, response->codecs[i]);
printf(" ptmap_len = %u\n", response->ptmap_len);
for(i=0;i<response->ptmap_len;i++) {
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
@@ -146,11 +149,12 @@ void test_mgcp_msg(void)
.conn_id = "11",
.conn_mode = MGCP_CONN_RECV_SEND,
.ptime = 20,
.ptmap = {
{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
},
.codecs[0] = CODEC_GSM_8000_1,
.codecs[1] = CODEC_AMR_8000_1,
.codecs[2] = CODEC_GSMEFR_8000_1,
.codecs_len = 1,
.ptmap[0].codec = CODEC_GSMEFR_8000_1,
.ptmap[0].pt = 96,
.ptmap_len = 1,
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
.x_osmo_osmux_cid = -1, /* wildcard */
@@ -158,7 +162,7 @@ void test_mgcp_msg(void)
if (mgcp)
talloc_free(mgcp);
mgcp = mgcp_client_init(ctx, conf);
mgcp = mgcp_client_init(ctx, &conf);
printf("\n");
@@ -175,9 +179,9 @@ void test_mgcp_msg(void)
mgcp_msg.presence =
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
mgcp_msg.ptmap_len = 2;
mgcp_msg.codecs_len = 2;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.ptmap_len = 1;
mgcp_msg.codecs_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated CRCX message (three codecs, one with custom pt):\n");
@@ -185,9 +189,9 @@ void test_mgcp_msg(void)
mgcp_msg.presence =
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
mgcp_msg.ptmap_len = 3;
mgcp_msg.codecs_len = 3;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.ptmap_len = 1;
mgcp_msg.codecs_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated MDCX message:\n");
@@ -205,9 +209,9 @@ void test_mgcp_msg(void)
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
mgcp_msg.ptmap_len = 2;
mgcp_msg.codecs_len = 2;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.ptmap_len = 1;
mgcp_msg.codecs_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated MDCX message (three codecs, one with custom pt):\n");
@@ -216,9 +220,9 @@ void test_mgcp_msg(void)
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
mgcp_msg.ptmap_len = 3;
mgcp_msg.codecs_len = 3;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.ptmap_len = 1;
mgcp_msg.codecs_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated DLCX message:\n");
@@ -326,10 +330,8 @@ void test_mgcp_client_cancel(void)
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
.ptime = 20,
.ptmap = {
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
},
.ptmap_len = 1
.codecs[0] = CODEC_AMR_8000_1,
.codecs_len = 1
};
printf("\n%s():\n", __func__);
@@ -337,7 +339,7 @@ void test_mgcp_client_cancel(void)
if (mgcp)
talloc_free(mgcp);
mgcp = mgcp_client_init(ctx, conf);
mgcp = mgcp_client_init(ctx, &conf);
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
trans_id = mgcp_msg_trans_id(msg);
@@ -529,7 +531,7 @@ void test_sdp_section_start(void)
OSMO_ASSERT(!failures);
}
static void test_map_str_to_codec(void)
static void test_map_pt_to_codec(void)
{
/* Full form */
OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
@@ -628,7 +630,7 @@ void test_mgcp_client_e1_epname(void)
if (mgcp)
talloc_free(mgcp);
mgcp = mgcp_client_init(ctx, conf);
mgcp = mgcp_client_init(ctx, &conf);
/* Valid endpoint names */
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
@@ -673,214 +675,6 @@ void test_mgcp_client_e1_epname(void)
OSMO_ASSERT(epname == NULL);
}
struct parse_response_test {
const char *body;
int expect_rc;
struct mgcp_response expect_params;
};
static struct parse_response_test parse_response_tests[] = {
{
.body = "200 2 OK\r\n"
"I: foo\r\n"
"\r\n"
"v=0\r\n"
"o=- name 23 IN IP4 0.0.0.0\r\n"
"s=-\r\n"
"c=IN IP4 1.2.3.4\r\n"
"t=0 0\r\n"
"m=audio 23 RTP/AVP 112 3\r\n" /* <-- implicit: 3 = GSM-FR */
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n",
.expect_rc = 0,
.expect_params = {
.audio_port = 23,
.audio_ip = "1.2.3.4",
.ptmap = {
{ .codec = CODEC_AMR_8000_1, .pt = 112 },
{ .codec = CODEC_GSM_8000_1, .pt = 3 },
},
.ptmap_len = 2,
},
},
{
.body = "200 2 OK\r\n"
"I: foo\r\n"
"\r\n"
"v=0\r\n"
"o=- name 23 IN IP4 0.0.0.0\r\n"
"s=-\r\n"
"c=IN IP4 1.2.3.4\r\n"
"t=0 0\r\n"
"m=audio 23 RTP/AVP 112 3\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=rtpmap:3 GSM/8000\r\n" /* 3 == GSM-FR implicitly, is an explicit entry a problem? */
"a=ptime:20\r\n",
.expect_rc = 0,
.expect_params = {
.audio_port = 23,
.audio_ip = "1.2.3.4",
.ptmap = {
{ .codec = CODEC_AMR_8000_1, .pt = 112 },
{ .codec = CODEC_GSM_8000_1, .pt = 3 }, /* no, not a problem */
},
.ptmap_len = 2,
},
},
{
.body = "200 2 OK\r\n"
"I: foo\r\n"
"\r\n"
"v=0\r\n"
"o=- name 23 IN IP4 0.0.0.0\r\n"
"s=-\r\n"
"c=IN IP4 1.2.3.4\r\n"
"t=0 0\r\n"
"m=audio 23 RTP/AVP 3\r\n" /* <-- 112 is missing here. Will it still appear? */
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n",
.expect_rc = 0,
.expect_params = {
.audio_port = 23,
.audio_ip = "1.2.3.4",
.ptmap = {
{ .codec = CODEC_GSM_8000_1, .pt = 3 },
{ .codec = CODEC_AMR_8000_1, .pt = 112 }, /* <-- yes, it was added to the end. */
},
.ptmap_len = 2,
},
},
{
/* test MGCP_MAX_CODECS */
.body = "200 2 OK\r\n"
"I: foo\r\n"
"\r\n"
"v=0\r\n"
"o=- name 23 IN IP4 0.0.0.0\r\n"
"s=-\r\n"
"c=IN IP4 1.2.3.4\r\n"
"t=0 0\r\n"
"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\n" /* <-- 10 codecs max */
"a=rtpmap:101 AMR/8000\r\n"
"a=rtpmap:102 AMR/8000\r\n"
"a=rtpmap:103 AMR/8000\r\n"
"a=rtpmap:104 AMR/8000\r\n"
"a=rtpmap:105 AMR/8000\r\n"
"a=rtpmap:106 AMR/8000\r\n"
"a=rtpmap:107 AMR/8000\r\n"
"a=rtpmap:108 AMR/8000\r\n"
"a=rtpmap:109 AMR/8000\r\n"
"a=rtpmap:110 AMR/8000\r\n"
"a=ptime:20\r\n",
.expect_rc = 0,
.expect_params = {
.audio_port = 23,
.audio_ip = "1.2.3.4",
.ptmap = {
{ .codec = CODEC_AMR_8000_1, .pt = 101 },
{ .codec = CODEC_AMR_8000_1, .pt = 102 },
{ .codec = CODEC_AMR_8000_1, .pt = 103 },
{ .codec = CODEC_AMR_8000_1, .pt = 104 },
{ .codec = CODEC_AMR_8000_1, .pt = 105 },
{ .codec = CODEC_AMR_8000_1, .pt = 106 },
{ .codec = CODEC_AMR_8000_1, .pt = 107 },
{ .codec = CODEC_AMR_8000_1, .pt = 108 },
{ .codec = CODEC_AMR_8000_1, .pt = 109 },
{ .codec = CODEC_AMR_8000_1, .pt = 110 },
},
.ptmap_len = 10,
},
},
{
/* test MGCP_MAX_CODECS */
.body = "200 2 OK\r\n"
"I: foo\r\n"
"\r\n"
"v=0\r\n"
"o=- name 23 IN IP4 0.0.0.0\r\n"
"s=-\r\n"
"c=IN IP4 1.2.3.4\r\n"
"t=0 0\r\n"
"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\n" /* <-- 11 > MGCP_MAX_CODECS */
"a=rtpmap:101 AMR/8000\r\n"
"a=rtpmap:102 AMR/8000\r\n"
"a=rtpmap:103 AMR/8000\r\n"
"a=rtpmap:104 AMR/8000\r\n"
"a=rtpmap:105 AMR/8000\r\n"
"a=rtpmap:106 AMR/8000\r\n"
"a=rtpmap:107 AMR/8000\r\n"
"a=rtpmap:108 AMR/8000\r\n"
"a=rtpmap:109 AMR/8000\r\n"
"a=rtpmap:110 AMR/8000\r\n"
"a=ptime:20\r\n",
.expect_rc = -EINVAL,
},
};
static void test_parse_response(void)
{
int i;
int failures = 0;
for (i = 0; i < ARRAY_SIZE(parse_response_tests); i++) {
int rc;
struct parse_response_test *t = &parse_response_tests[i];
struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
int p;
r->body = talloc_strdup(r, t->body);
//printf("\n%s() test [%d]:\n", __func__, i);
fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
rc = mgcp_response_parse_params(r);
fprintf(stderr, "got rc=%d\n", rc);
if (rc != t->expect_rc) {
fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
failures++;
}
if (rc) {
talloc_free(r);
continue;
}
fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
failures++;
}
fprintf(stderr, "got audio_port=%u\n", r->audio_port);
if (r->audio_port != t->expect_params.audio_port) {
fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
failures++;
}
for (p = 0; p < r->ptmap_len; p++) {
struct ptmap *got = &r->ptmap[p];
struct ptmap *expect = NULL;
fprintf(stderr, " %d %s\n", got->pt, osmo_mgcpc_codec_name(got->codec));
if (p >= t->expect_params.ptmap_len) {
fprintf(stderr, " - ERROR: too many codec entries\n");
failures++;
continue;
}
expect = &t->expect_params.ptmap[p];
if (ptmap_cmp(got, expect)) {
fprintf(stderr, " - ERROR: expected: %d %s\n",
expect->pt, osmo_mgcpc_codec_name(expect->codec));
failures++;
}
}
talloc_free(r);
}
OSMO_ASSERT(!failures);
}
static const struct log_info_cat log_categories[] = {
};
@@ -903,17 +697,15 @@ int main(int argc, char **argv)
log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
conf = mgcp_client_conf_alloc(ctx);
mgcp_client_conf_init(&conf);
test_mgcp_msg();
test_mgcp_client_cancel();
test_sdp_section_start();
test_map_codec_to_pt_and_map_pt_to_codec();
test_map_str_to_codec();
test_map_pt_to_codec();
test_mgcp_client_e1_epname();
test_parse_response();
printf("Done\n");
fprintf(stderr, "Done\n");
return EXIT_SUCCESS;

View File

@@ -1,6 +1,5 @@
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
DLMGCP MGW(mgw) Message buffer too small, can not generate MGCP message (SDP)
DLMGCP MGW(mgw) Failed to add SDP, can not generate MGCP message
DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
test_mgcp_client_cancel():
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
@@ -11,7 +10,6 @@ DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
- cancel succeeds
DLMGCP MGW(mgw) Canceled transaction 1
- late response gets discarded
DLMGCP MGW(mgw) MGCP link to MGW now considered UP
DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
- canceling again does nothing
@@ -137,51 +135,4 @@ DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw),
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
test_parse_response() test [0]:
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
got rc=0
got audio_ip="1.2.3.4"
got audio_port=23
112 AMR/8000/1
3 GSM/8000/1
test_parse_response() test [1]:
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:3 GSM/8000\r\na=ptime:20\r\n"
got rc=0
got audio_ip="1.2.3.4"
got audio_port=23
112 AMR/8000/1
3 GSM/8000/1
test_parse_response() test [2]:
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
DLMGCP error in MGCP message: 'a=rtpmap:112' has no matching entry in 'm=audio ... 112'
got rc=0
got audio_ip="1.2.3.4"
got audio_port=23
3 GSM/8000/1
112 AMR/8000/1
test_parse_response() test [3]:
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR/8"
got rc=0
got audio_ip="1.2.3.4"
got audio_port=23
101 AMR/8000/1
102 AMR/8000/1
103 AMR/8000/1
104 AMR/8000/1
105 AMR/8000/1
106 AMR/8000/1
107 AMR/8000/1
108 AMR/8000/1
109 AMR/8000/1
110 AMR/8000/1
test_parse_response() test [4]:
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR"
DLMGCP SDP: can parse only up to 10 payload type numbers
DLMGCP Failed to parse SDP parameter payload types (RTP/AVP)
got rc=-22
Done