mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-04 05:53:26 +00:00
Compare commits
2 Commits
master
...
jolly/asci
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05e69d52b9 | ||
|
|
62d97f4463 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,8 +8,6 @@ Makefile
|
|||||||
Makefile.in
|
Makefile.in
|
||||||
bscconfig.h
|
bscconfig.h
|
||||||
bscconfig.h.in
|
bscconfig.h.in
|
||||||
include/osmocom/mgcp_client/mgcp_common.h
|
|
||||||
include/osmocom/mgcp_client/version.h
|
|
||||||
src/osmo-mgw/osmo-mgw
|
src/osmo-mgw/osmo-mgw
|
||||||
*.*~
|
*.*~
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pkgconfig_DATA = \
|
|||||||
BUILT_SOURCES = $(top_srcdir)/.version
|
BUILT_SOURCES = $(top_srcdir)/.version
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
.version \
|
.version \
|
||||||
README.md \
|
contrib/osmo-mgw.spec.in \
|
||||||
debian \
|
debian \
|
||||||
git-version-gen \
|
git-version-gen \
|
||||||
osmoappdesc.py \
|
osmoappdesc.py \
|
||||||
|
|||||||
24
README
Normal file
24
README
Normal 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
102
README.md
@@ -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.
|
|
||||||
40
TODO-RELEASE
40
TODO-RELEASE
@@ -1,12 +1,28 @@
|
|||||||
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
# When cleaning up this file upon a release:
|
||||||
# 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
|
# - Note that the release version number is entirely unrelated to the API
|
||||||
# LIBVERSION=c:r:a
|
# versions. A release version 5.2.3 may happily have an API version of 42:7:5.
|
||||||
# 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.
|
# - Bump API version in src/lib*/Makefile.am files according to chapter
|
||||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
# "Library interface versions" of the libtool documentation.
|
||||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
#library what description / commit summary line
|
#
|
||||||
libosmocore bump_dep; workaround Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
|
# - Iff the 'current' API version has changed, rename debian/lib*.install
|
||||||
has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
|
#
|
||||||
libosmocodec bump_dep We depend on the additions of I2c510ac62a0786c137115c45eee7a48b9736265f
|
# 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
|
||||||
|
libosmo-mgcp-client NEW API mgcp_client_conf_alloc()
|
||||||
|
libosmo-mgcp-client DEPRECATED mgcp_client_conf_init()
|
||||||
16
configure.ac
16
configure.ac
@@ -44,14 +44,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
|
|||||||
AC_SUBST(LIBRARY_DLSYM)
|
AC_SUBST(LIBRARY_DLSYM)
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.11.0)
|
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 1.11.0)
|
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
|
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
|
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
|
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0)
|
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
|
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.4.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.0)
|
|
||||||
|
|
||||||
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
||||||
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
||||||
@@ -205,4 +204,5 @@ AC_OUTPUT(
|
|||||||
doc/manuals/Makefile
|
doc/manuals/Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/systemd/Makefile
|
contrib/systemd/Makefile
|
||||||
|
contrib/osmo-mgw.spec
|
||||||
Makefile)
|
Makefile)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export deps inst
|
|||||||
osmo-clean-workspace.sh
|
osmo-clean-workspace.sh
|
||||||
|
|
||||||
mkdir "$deps" || true
|
mkdir "$deps" || true
|
||||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
|
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
|
||||||
|
|
||||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
|
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
|
|||||||
export LD_LIBRARY_PATH="$inst/lib"
|
export LD_LIBRARY_PATH="$inst/lib"
|
||||||
export PATH="$inst/bin:$PATH"
|
export PATH="$inst/bin:$PATH"
|
||||||
|
|
||||||
osmo-build-dep.sh libosmo-netif "" --disable-doxygen
|
|
||||||
osmo-build-dep.sh libosmo-abis
|
osmo-build-dep.sh libosmo-abis
|
||||||
|
osmo-build-dep.sh libosmo-netif
|
||||||
|
|
||||||
# Additional configure options and depends
|
# Additional configure options and depends
|
||||||
CONFIG=""
|
CONFIG=""
|
||||||
|
|||||||
137
contrib/osmo-mgw.spec.in
Normal file
137
contrib/osmo-mgw.spec.in
Normal 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
|
||||||
@@ -5,15 +5,11 @@ Wants=network-online.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
LimitNOFILE=65536
|
|
||||||
StateDirectory=osmocom
|
StateDirectory=osmocom
|
||||||
WorkingDirectory=%S/osmocom
|
WorkingDirectory=%S/osmocom
|
||||||
Restart=always
|
Restart=always
|
||||||
User=osmocom
|
|
||||||
Group=osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
|
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
AmbientCapabilities=CAP_SYS_NICE
|
|
||||||
# CPU scheduling policy:
|
# CPU scheduling policy:
|
||||||
CPUSchedulingPolicy=rr
|
CPUSchedulingPolicy=rr
|
||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||||
|
|||||||
220
debian/changelog
vendored
220
debian/changelog
vendored
@@ -1,223 +1,3 @@
|
|||||||
osmo-mgw (1.14.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* jenkins.sh: libosmo-netif no longer depends on libosmo-abis
|
|
||||||
* jenkins.sh: Use --disable-doxygen configure param
|
|
||||||
* mgcp-client: Fix wrong value passed to strerror()
|
|
||||||
* mgcp_client_internal.h: Add missing header dependency
|
|
||||||
* mgcp-cli: Mark iofd ptr as NULL when freed
|
|
||||||
* mgcp-cli: Improve error handling around mgcp_msg_gen() return
|
|
||||||
* mgcp-cli: Fix filling in wrong local IP address of SDP Origin o=
|
|
||||||
* mgw: Drop own MGCP extension 'noanswer'
|
|
||||||
* cosmetic: mgw: Fix indentation whitespace
|
|
||||||
* mgcp-client: Fix regression checking null ptr
|
|
||||||
* mgw: Rename and move code freeing endp connection
|
|
||||||
* mgw: Rename and move several get_conn funcs acting on endp object
|
|
||||||
* mgw: mgcp_network.c: Simplify use of conn_rtp ptr
|
|
||||||
* mgw: Clean up access to conn_rtp from conn
|
|
||||||
* mgw: Avoid 2nd lookup of conn in endp during CRCX
|
|
||||||
* cosmetic: mgw: iuup: Update comment
|
|
||||||
* mgw: constify mgcp_endp_avail() param
|
|
||||||
* mgcp_endp: Add helpers accessing endp connections
|
|
||||||
* mgw: mgcp_protocol: assert freeing last conn allows creating new conn
|
|
||||||
* mgw: Split conn mode parsing and applying into conn
|
|
||||||
* mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables
|
|
||||||
* mgw: Use bool instead of int in local var
|
|
||||||
* Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port()
|
|
||||||
* mgw: Split mgcp_rtp_end to its own file
|
|
||||||
* mgw: Introduce mgcp_rtp_end_init()
|
|
||||||
* mgw: Introduce struct mgcp_codecset struct
|
|
||||||
* mgw: Cleanup rtp_endp fields in its own function
|
|
||||||
* mgw: Move force_ptime logic outside of main CRCX func handler
|
|
||||||
* mgw: Move several params setting to mgcp_rtp_end_init()
|
|
||||||
* mgw: Simplify and redo code around ssrc patch feature
|
|
||||||
* mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
|
|
||||||
* mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
|
|
||||||
* mgw: CRCX: Split mgcp header pars parsing into a previous step
|
|
||||||
* mgw: MDCX: Split mgcp header pars parsing into a previous step
|
|
||||||
* mgw: DLCX: Split mgcp header pars parsing into a previous step
|
|
||||||
* mgw: Decouple SDP parsing step from conn obj update
|
|
||||||
* mgw: Remove wrong TODO comment
|
|
||||||
* mgw: MDCX: Simplify early return code paths
|
|
||||||
|
|
||||||
[ Mychaela N. Falconia ]
|
|
||||||
* E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
|
|
||||||
* E1: replace idle_tf_efr[] with a better version
|
|
||||||
* E1: replace idle_tf_fr[] with a better version
|
|
||||||
|
|
||||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 12 Feb 2025 12:30:33 +0100
|
|
||||||
|
|
||||||
osmo-mgw (1.13.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
|
|
||||||
|
|
||||||
osmo-mgw (1.11.0) unstable; urgency=medium
|
osmo-mgw (1.11.0) unstable; urgency=medium
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
[ Pau Espin Pedrol ]
|
||||||
|
|||||||
12
debian/control
vendored
12
debian/control
vendored
@@ -6,10 +6,10 @@ Build-Depends: debhelper (>= 10),
|
|||||||
dh-autoreconf,
|
dh-autoreconf,
|
||||||
pkg-config,
|
pkg-config,
|
||||||
autotools-dev,
|
autotools-dev,
|
||||||
libosmocore-dev (>= 1.11.0),
|
libosmocore-dev (>= 1.8.0),
|
||||||
libosmo-netif-dev (>= 1.6.0),
|
libosmo-netif-dev (>= 1.3.0),
|
||||||
libosmo-abis-dev (>= 2.0.0),
|
libosmo-abis-dev (>= 1.4.0),
|
||||||
osmo-gsm-manuals-dev (>= 1.6.0)
|
osmo-gsm-manuals-dev (>= 1.4.0)
|
||||||
Standards-Version: 3.9.8
|
Standards-Version: 3.9.8
|
||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
||||||
Vcs-Browser: 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}
|
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
||||||
|
|
||||||
Package: libosmo-mgcp-client14
|
Package: libosmo-mgcp-client11
|
||||||
Section: libs
|
Section: libs
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Multi-Arch: same
|
Multi-Arch: same
|
||||||
@@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
|
|||||||
Section: libdevel
|
Section: libdevel
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Multi-Arch: same
|
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
|
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
|
||||||
|
|
||||||
Package: osmo-mgw-doc
|
Package: osmo-mgw-doc
|
||||||
|
|||||||
38
debian/postinst
vendored
38
debian/postinst
vendored
@@ -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#
|
|
||||||
@@ -1,25 +1,20 @@
|
|||||||
!
|
!
|
||||||
! MGCP configuration example
|
! 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_input
|
||||||
e1_line 0 driver dahdi
|
e1_line 0 driver dahdi
|
||||||
e1_line 0 port 0
|
e1_line 0 port 0
|
||||||
mgcp
|
mgcp
|
||||||
bind ip 127.0.0.1
|
bind ip 127.0.0.1
|
||||||
rtp port-range 4002 16001
|
rtp port-range 4002 16000
|
||||||
rtp bind-ip 127.0.0.1
|
rtp bind-ip 127.0.0.1
|
||||||
rtp ip-probing
|
rtp ip-probing
|
||||||
rtp ip-dscp 46
|
rtp ip-dscp 46
|
||||||
bind port 2427
|
bind port 2427
|
||||||
|
sdp audio payload number 98
|
||||||
|
sdp audio payload name GSM
|
||||||
number endpoints 512
|
number endpoints 512
|
||||||
|
loop 0
|
||||||
force-realloc 1
|
force-realloc 1
|
||||||
rtcp-omit
|
rtcp-omit
|
||||||
rtp-patch ssrc
|
rtp-patch ssrc
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
!
|
!
|
||||||
! MGCP configuration example
|
! 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
|
mgcp
|
||||||
bind ip 127.0.0.1
|
bind ip 127.0.0.1
|
||||||
rtp port-range 4002 16001
|
rtp port-range 4002 16000
|
||||||
rtp bind-ip 127.0.0.1
|
rtp bind-ip 127.0.0.1
|
||||||
rtp ip-probing
|
rtp ip-probing
|
||||||
rtp ip-dscp 46
|
rtp ip-dscp 46
|
||||||
bind port 2427
|
bind port 2427
|
||||||
|
sdp audio payload number 98
|
||||||
|
sdp audio payload name GSM
|
||||||
number endpoints 512
|
number endpoints 512
|
||||||
|
loop 0
|
||||||
force-realloc 1
|
force-realloc 1
|
||||||
rtcp-omit
|
rtcp-omit
|
||||||
rtp-patch ssrc
|
rtp-patch ssrc
|
||||||
|
|||||||
@@ -70,85 +70,3 @@ a=ptime:40
|
|||||||
=== `X-Osmux`
|
=== `X-Osmux`
|
||||||
|
|
||||||
See <<mgcp-extension-osmux>>
|
See <<mgcp-extension-osmux>>
|
||||||
|
|
||||||
=== Non-standard SDP codec parameters
|
|
||||||
|
|
||||||
CRCX command message normally includes an SDP block that specifies the RTP
|
|
||||||
address of the connecting peer and the list of codecs accepted by that entity.
|
|
||||||
Codec specifications may include optional parameters given via `a=fmtp` lines;
|
|
||||||
one well-known parameter is `octet-align`, defined for AMR and AMR-WB codecs.
|
|
||||||
|
|
||||||
In addition to standard (RFC-defined) codec parameters (of which the
|
|
||||||
just-mentioned `octet-align` parameter is the only one implemented so far),
|
|
||||||
OsmoMGW also understands some non-standard (Osmocom-private) codec parameters
|
|
||||||
as listed below.
|
|
||||||
These Osmocom-private codec parameters are meaningful only in the context
|
|
||||||
of OsmoBSC driving an E1 Abis MGW, which may be either OsmoMGW or a specialized
|
|
||||||
third-party replacement.
|
|
||||||
|
|
||||||
The MGCP extension described in this section is meaningful only for E1
|
|
||||||
endpoints - it has absolutely no effect on `rtpbridge` endpoints!
|
|
||||||
|
|
||||||
==== `tw-ts-001` parameter for FR and EFR codecs
|
|
||||||
|
|
||||||
GSM Full Rate codec is known in SDP as `GSM`; GSM Enhanced Full Rate codec
|
|
||||||
is known in SDP as `GSM-EFR`.
|
|
||||||
When either codec is to be transported in RTP, there is a choice between
|
|
||||||
two different payload formats: RFC 3551 or TW-TS-001.
|
|
||||||
RFC 3551 is the standard in non-GSM Internet applications, and it is the
|
|
||||||
format specified in later 3GPP releases for IP-based transport of
|
|
||||||
compressed speech - however, it exhibits functional regressions compared
|
|
||||||
to the original TRAU-UL frame format of GSM 08.60.
|
|
||||||
TW-TS-001 is an enhanced alternative payload format for the same codecs
|
|
||||||
that restores the original functionality and semantics of TRAU-UL frames.
|
|
||||||
|
|
||||||
In the context of CRCX or MDCX command messages from OsmoBSC to an E1 Abis MGW,
|
|
||||||
`tw-ts-001` codec parameter (attached to either `GSM` or `GSM-EFR` codec)
|
|
||||||
instructs the MGW whether or not it should emit the extended payload format
|
|
||||||
of TW-TS-001 for GSM uplink traffic converted to RTP.
|
|
||||||
In the absence of this parameter, IETF-standard and 3GPP-standard RFC 3551
|
|
||||||
format is emitted; if TW-TS-001 output is desired, please specify
|
|
||||||
`tw-ts-001=1` on the appropriate `a=fmtp` line.
|
|
||||||
|
|
||||||
.Example: `CRCX` message requesting EFR codec with TW-TS-001 extensions
|
|
||||||
----
|
|
||||||
CRCX 2 ds/e1-0/s-2/su16-2@mgw MGCP 1.0
|
|
||||||
M: recvonly
|
|
||||||
C: 2
|
|
||||||
L: p:20
|
|
||||||
|
|
||||||
v=0
|
|
||||||
c=IN IP4 123.12.12.123
|
|
||||||
m=audio 1234 RTP/AVP 110
|
|
||||||
a=rtpmap:110 GSM-EFR/8000/1
|
|
||||||
a=fmtp:110 tw-ts-001=1
|
|
||||||
----
|
|
||||||
|
|
||||||
==== `tw-ts-002` parameter for HR codec
|
|
||||||
|
|
||||||
GSM Half Rate codec is known in SDP as `GSM-HR-08`.
|
|
||||||
The same dichotomy that exists between RFC 3551 and TW-TS-001 RTP payload
|
|
||||||
formats for FR and EFR codecs also exists for HR codec, except that
|
|
||||||
the two opposing alternatives are now RFC 5993 and TW-TS-002.
|
|
||||||
|
|
||||||
In the context of CRCX or MDCX command messages from OsmoBSC to an E1 Abis MGW,
|
|
||||||
`tw-ts-002` codec parameter (attached to `GSM-HR-08` codec)
|
|
||||||
instructs the MGW whether or not it should emit the extended payload format
|
|
||||||
of TW-TS-002 for GSM uplink traffic converted to RTP.
|
|
||||||
In the absence of this parameter, IETF-standard and 3GPP-standard RFC 5993
|
|
||||||
format is emitted; if TW-TS-002 output is desired, please specify
|
|
||||||
`tw-ts-002=1` on the appropriate `a=fmtp` line.
|
|
||||||
|
|
||||||
.Example: `CRCX` message requesting HR codec with TW-TS-002 extensions
|
|
||||||
----
|
|
||||||
CRCX 2 ds/e1-0/s-2/su8-2@mgw MGCP 1.0
|
|
||||||
M: recvonly
|
|
||||||
C: 2
|
|
||||||
L: p:20
|
|
||||||
|
|
||||||
v=0
|
|
||||||
c=IN IP4 123.12.12.123
|
|
||||||
m=audio 1234 RTP/AVP 111
|
|
||||||
a=rtpmap:111 GSM-HR-08/8000/1
|
|
||||||
a=fmtp:111 tw-ts-002=1
|
|
||||||
----
|
|
||||||
|
|||||||
@@ -23,20 +23,3 @@ arguments:
|
|||||||
Disable colors for logging to stderr. This has mostly been
|
Disable colors for logging to stderr. This has mostly been
|
||||||
deprecated by VTY based logging configuration, see <<logging>>
|
deprecated by VTY based logging configuration, see <<logging>>
|
||||||
for more information.
|
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.
|
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ nobase_include_HEADERS = \
|
|||||||
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
|
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
|
||||||
osmocom/mgcp_client/mgcp_client_fsm.h \
|
osmocom/mgcp_client/mgcp_client_fsm.h \
|
||||||
osmocom/mgcp_client/mgcp_client_pool.h \
|
osmocom/mgcp_client/mgcp_client_pool.h \
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
|
||||||
osmocom/mgcp/mgcp.h \
|
osmocom/mgcp/mgcp.h \
|
||||||
osmocom/mgcp/mgcp_common.h \
|
osmocom/mgcp/mgcp_common.h \
|
||||||
osmocom/mgcp/osmux.h \
|
osmocom/mgcp/osmux.h \
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
vty.h \
|
vty.h \
|
||||||
mgcp_msg.h \
|
mgcp_msg.h \
|
||||||
mgcp_codec.h \
|
|
||||||
mgcp_conn.h \
|
mgcp_conn.h \
|
||||||
mgcp_stat.h \
|
mgcp_stat.h \
|
||||||
mgcp_endp.h \
|
mgcp_endp.h \
|
||||||
@@ -14,5 +13,4 @@ noinst_HEADERS = \
|
|||||||
mgcp_network.h \
|
mgcp_network.h \
|
||||||
mgcp_protocol.h \
|
mgcp_protocol.h \
|
||||||
mgcp_iuup.h \
|
mgcp_iuup.h \
|
||||||
mgcp_rtp_end.h \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/osmo_io.h>
|
|
||||||
#include <osmocom/core/write_queue.h>
|
#include <osmocom/core/write_queue.h>
|
||||||
#include <osmocom/core/timer.h>
|
#include <osmocom/core/timer.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
@@ -40,8 +39,6 @@
|
|||||||
|
|
||||||
#include "mgcp_ratectr.h"
|
#include "mgcp_ratectr.h"
|
||||||
|
|
||||||
extern void *tall_mgw_ctx;
|
|
||||||
|
|
||||||
#define RTP_PORT_DEFAULT_RANGE_START 16002
|
#define RTP_PORT_DEFAULT_RANGE_START 16002
|
||||||
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
|
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
|
||||||
|
|
||||||
@@ -52,6 +49,11 @@ struct mgcp_endpoint;
|
|||||||
struct mgcp_config;
|
struct mgcp_config;
|
||||||
struct mgcp_trunk;
|
struct mgcp_trunk;
|
||||||
struct mgcp_rtp_end;
|
struct mgcp_rtp_end;
|
||||||
|
|
||||||
|
#define MGCP_ENDP_CRCX 1
|
||||||
|
#define MGCP_ENDP_DLCX 2
|
||||||
|
#define MGCP_ENDP_MDCX 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* what to do with the msg?
|
* what to do with the msg?
|
||||||
* - continue as usual?
|
* - continue as usual?
|
||||||
@@ -68,10 +70,12 @@ typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
|||||||
/**
|
/**
|
||||||
* Return:
|
* Return:
|
||||||
* < 0 in case no audio was processed
|
* < 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,
|
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;
|
struct mgcp_conn_rtp;
|
||||||
|
|
||||||
@@ -130,6 +134,12 @@ struct mgcp_config {
|
|||||||
char source_addr[INET6_ADDRSTRLEN];
|
char source_addr[INET6_ADDRSTRLEN];
|
||||||
char call_agent_addr[INET6_ADDRSTRLEN];
|
char call_agent_addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
/* RTP processing */
|
||||||
|
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 osmo_wqueue gw_fd;
|
||||||
|
|
||||||
struct mgcp_port_range net_ports;
|
struct mgcp_port_range net_ports;
|
||||||
@@ -198,5 +208,6 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
|
|||||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
|
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_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
|
||||||
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len);
|
uint8_t prio);
|
||||||
|
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_common.h>
|
|
||||||
|
|
||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||||
@@ -12,37 +8,14 @@
|
|||||||
|
|
||||||
#define PTYPE_UNDEFINED (-1)
|
#define PTYPE_UNDEFINED (-1)
|
||||||
|
|
||||||
struct mgcp_rtp_codec {
|
struct mgcp_conn_rtp;
|
||||||
uint32_t rate;
|
|
||||||
int channels;
|
|
||||||
uint32_t frame_duration_num;
|
|
||||||
uint32_t frame_duration_den;
|
|
||||||
|
|
||||||
int payload_type;
|
|
||||||
char audio_name[64];
|
|
||||||
char subtype_name[64];
|
|
||||||
|
|
||||||
bool param_present;
|
|
||||||
struct mgcp_codec_param param;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
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_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
|
||||||
bool mgcp_codec_amr_is_octet_aligned(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);
|
||||||
struct mgcp_rtp_codecset {
|
|
||||||
/* currently selected audio codec */
|
|
||||||
struct mgcp_rtp_codec *codec;
|
|
||||||
/* array with assigned audio codecs to choose from (SDP) */
|
|
||||||
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
|
|
||||||
/* number of assigned audio codecs (SDP) */
|
|
||||||
unsigned int codecs_assigned;
|
|
||||||
};
|
|
||||||
|
|
||||||
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
|
|
||||||
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
|
|
||||||
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
|
|
||||||
const char *audio_name, const struct mgcp_codec_param *param);
|
|
||||||
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
|
|
||||||
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
|
|
||||||
const char *subtype_name, unsigned int match_nr);
|
|
||||||
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);
|
|
||||||
|
|||||||
@@ -63,20 +63,16 @@ enum mgcp_x_osmo_ign {
|
|||||||
struct mgcp_codec_param {
|
struct mgcp_codec_param {
|
||||||
bool amr_octet_aligned_present;
|
bool amr_octet_aligned_present;
|
||||||
bool amr_octet_aligned;
|
bool amr_octet_aligned;
|
||||||
bool fr_efr_twts001_present;
|
|
||||||
bool fr_efr_twts001;
|
|
||||||
bool hr_twts002_present;
|
|
||||||
bool hr_twts002;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Ensure that the msg->l2h is NUL terminated. */
|
/* Ensure that the msg->l2h is NUL terminated. */
|
||||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
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')
|
if (tail[-1] == '\0')
|
||||||
/* nothing to do */;
|
/* nothing to do */;
|
||||||
else if (msgb_tailroom(msg) > 0)
|
else if (msgb_tailroom(msg) > 0)
|
||||||
msgb_put_u8(msg, (uint8_t)'\0');
|
tail[0] = '\0';
|
||||||
else if (tail[-1] == '\r' || tail[-1] == '\n')
|
else if (tail[-1] == '\r' || tail[-1] == '\n')
|
||||||
tail[-1] = '\0';
|
tail[-1] = '\0';
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -24,14 +24,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <osmocom/mgcp/mgcp.h>
|
#include <osmocom/mgcp/mgcp.h>
|
||||||
#include <osmocom/mgcp/mgcp_common.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_network.h>
|
#include <osmocom/mgcp/mgcp_network.h>
|
||||||
#include <osmocom/mgcp/osmux.h>
|
#include <osmocom/mgcp/osmux.h>
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
#include <osmocom/core/rate_ctr.h>
|
#include <osmocom/core/rate_ctr.h>
|
||||||
#include <osmocom/core/utils.h>
|
|
||||||
#include <osmocom/gsm/iuup.h>
|
#include <osmocom/gsm/iuup.h>
|
||||||
#include <osmocom/mgcp/mgcp_rtp_end.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
|
#define LOGPCONN(conn, cat, level, fmt, args...) \
|
||||||
@@ -52,11 +49,6 @@ enum mgcp_conn_rtp_type {
|
|||||||
MGCP_RTP_OSMUX,
|
MGCP_RTP_OSMUX,
|
||||||
MGCP_RTP_IUUP,
|
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
|
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||||
* contains a useful connection description (currently only RTP) */
|
* contains a useful connection description (currently only RTP) */
|
||||||
@@ -240,16 +232,15 @@ static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
|
|||||||
return conn->type == MGCP_RTP_IUUP;
|
return conn->type == MGCP_RTP_IUUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn)
|
|
||||||
{
|
|
||||||
OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
|
|
||||||
return &conn->u.rtp;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
||||||
enum mgcp_conn_type type, char *name);
|
enum mgcp_conn_type type, char *name);
|
||||||
void mgcp_conn_free(struct mgcp_conn *conn);
|
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
|
||||||
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode);
|
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
|
||||||
|
const char *id);
|
||||||
|
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
|
||||||
|
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
|
||||||
|
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
|
||||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
|
char *mgcp_conn_dump(struct mgcp_conn *conn);
|
||||||
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
|
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
|
||||||
|
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
|
||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
|
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8
|
|||||||
static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
|
static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
|
||||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
|
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
|
||||||
int mgcp_e1_endp_update(struct mgcp_endpoint *endp);
|
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, uint8_t ts);
|
||||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
|
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ struct mgcp_endpoint {
|
|||||||
struct osmo_fsm_inst *trau_sync_fi;
|
struct osmo_fsm_inst *trau_sync_fi;
|
||||||
struct osmo_trau2rtp_state *trau_rtp_st;
|
struct osmo_trau2rtp_state *trau_rtp_st;
|
||||||
uint8_t last_amr_ft;
|
uint8_t last_amr_ft;
|
||||||
uint8_t rtp_extensions;
|
|
||||||
struct mgcp_rtp_codec *last_codec;
|
struct mgcp_rtp_codec *last_codec;
|
||||||
} e1;
|
} e1;
|
||||||
|
|
||||||
@@ -132,28 +131,18 @@ struct mgcp_endpoint {
|
|||||||
|
|
||||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
|
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
|
||||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
|
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
|
||||||
int mgcp_endp_update(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb);
|
void mgcp_endp_update(struct mgcp_endpoint *endp);
|
||||||
bool mgcp_endp_is_wildcarded(const char *epname);
|
bool mgcp_endp_is_wildcarded(const char *epname);
|
||||||
bool mgcp_endp_is_null(const char *epname);
|
bool mgcp_endp_is_null(const char *epname);
|
||||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||||
const struct mgcp_trunk *trunk);
|
const struct mgcp_trunk *trunk);
|
||||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
||||||
struct mgcp_config *cfg);
|
struct mgcp_config *cfg);
|
||||||
bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
|
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
|
||||||
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
|
|
||||||
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
|
|
||||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||||
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
|
|
||||||
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
|
|
||||||
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
||||||
const struct mgcp_trunk *trunk);
|
const struct mgcp_trunk *trunk);
|
||||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
||||||
const struct mgcp_trunk *trunk);
|
const struct mgcp_trunk *trunk);
|
||||||
void mgcp_endp_update_lco(struct mgcp_endpoint *endp, const struct mgcp_lco *lco);
|
|
||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
||||||
|
|
||||||
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
|
|
||||||
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
|
|
||||||
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
|
|
||||||
const char *id);
|
|
||||||
|
|||||||
@@ -31,4 +31,3 @@ void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp);
|
|||||||
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg);
|
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg);
|
||||||
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg);
|
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg);
|
||||||
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);
|
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);
|
||||||
int mgcp_conn_iuup_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn_rtp);
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <osmocom/mgcp/mgcp_common.h>
|
|
||||||
|
|
||||||
struct mgcp_conn;
|
struct mgcp_conn;
|
||||||
struct mgcp_parse_data;
|
struct mgcp_parse_data;
|
||||||
struct mgcp_endpoint;
|
struct mgcp_endpoint;
|
||||||
@@ -36,14 +34,14 @@ struct mgcp_trunk;
|
|||||||
|
|
||||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
|
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
|
||||||
|
|
||||||
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg);
|
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
|
||||||
|
struct mgcp_conn *conn);
|
||||||
|
|
||||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
|
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
|
||||||
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata);
|
|
||||||
|
|
||||||
int mgcp_parse_osmux_cid(const char *line);
|
int mgcp_parse_osmux_cid(const char *line);
|
||||||
|
|
||||||
bool mgcp_check_param(const char *line);
|
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
|
||||||
|
|
||||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
|
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/osmo_io.h>
|
|
||||||
|
|
||||||
#include <osmocom/mgcp/mgcp.h>
|
#include <osmocom/mgcp/mgcp.h>
|
||||||
|
|
||||||
@@ -74,6 +73,66 @@ struct mgcp_rtp_state {
|
|||||||
uint32_t alt_rtp_tx_ssrc;
|
uint32_t alt_rtp_tx_ssrc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mgcp_rtp_codec {
|
||||||
|
uint32_t rate;
|
||||||
|
int channels;
|
||||||
|
uint32_t frame_duration_num;
|
||||||
|
uint32_t frame_duration_den;
|
||||||
|
|
||||||
|
int payload_type;
|
||||||
|
char audio_name[64];
|
||||||
|
char subtype_name[64];
|
||||||
|
|
||||||
|
bool param_present;
|
||||||
|
struct mgcp_codec_param param;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
||||||
|
struct mgcp_rtp_end {
|
||||||
|
/* remote IP address of the RTP socket */
|
||||||
|
struct osmo_sockaddr addr;
|
||||||
|
|
||||||
|
/* in network byte order */
|
||||||
|
int rtcp_port;
|
||||||
|
|
||||||
|
/* currently selected audio codec */
|
||||||
|
struct mgcp_rtp_codec *codec;
|
||||||
|
|
||||||
|
/* array with assigned audio codecs to choose from (SDP) */
|
||||||
|
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
|
||||||
|
|
||||||
|
/* number of assigned audio codecs (SDP) */
|
||||||
|
unsigned int codecs_assigned;
|
||||||
|
|
||||||
|
/* per endpoint data */
|
||||||
|
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! */
|
||||||
|
int force_output_ptime;
|
||||||
|
|
||||||
|
/* RTP patching */
|
||||||
|
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
|
||||||
|
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
|
||||||
|
int force_aligned_timing;
|
||||||
|
bool rfc5993_hr_convert;
|
||||||
|
|
||||||
|
/* Each end has a separate socket for RTP and RTCP */
|
||||||
|
struct osmo_fd rtp;
|
||||||
|
struct osmo_fd rtcp;
|
||||||
|
|
||||||
|
/* local UDP port number of the RTP socket; RTCP is +1 */
|
||||||
|
int local_port;
|
||||||
|
/* where the endpoint RTP connection binds to, set during CRCX and
|
||||||
|
* possibly updated during MDCX */
|
||||||
|
char local_addr[INET6_ADDRSTRLEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
|
||||||
|
|
||||||
struct mgcp_rtp_tap {
|
struct mgcp_rtp_tap {
|
||||||
/* is this tap active (1) or not (0) */
|
/* is this tap active (1) or not (0) */
|
||||||
int enabled;
|
int enabled;
|
||||||
@@ -91,13 +150,28 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
|
|||||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
|
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
|
||||||
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||||
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
|
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
|
||||||
|
struct mgcp_conn_rtp *conn);
|
||||||
|
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||||
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
||||||
struct mgcp_rtp_state *state,
|
struct mgcp_rtp_state *state,
|
||||||
struct mgcp_rtp_end *rtp_end,
|
struct mgcp_rtp_end *rtp_end,
|
||||||
struct osmo_sockaddr *addr, struct msgb *msg);
|
struct osmo_sockaddr *addr, struct msgb *msg);
|
||||||
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
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,
|
||||||
|
char *data, int *len, int buf_size);
|
||||||
|
|
||||||
|
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||||
|
struct mgcp_conn_rtp *conn_dst,
|
||||||
|
struct mgcp_conn_rtp *conn_src);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/* internal RTP Annex A counting */
|
/* internal RTP Annex A counting */
|
||||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||||
const uint16_t seq, const int32_t transit,
|
const uint16_t seq, const int32_t transit,
|
||||||
@@ -107,7 +181,7 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
|
|||||||
int id, int inc);
|
int id, int inc);
|
||||||
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
|
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
|
||||||
int id);
|
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);
|
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);
|
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
|
||||||
|
|||||||
@@ -1,140 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
/* Internal structure while parsing a request */
|
||||||
#include <sys/socket.h>
|
struct mgcp_parse_data {
|
||||||
|
struct mgcp_config *cfg;
|
||||||
#include <osmocom/core/utils.h>
|
char *epname;
|
||||||
#include <osmocom/core/socket.h>
|
char *trans;
|
||||||
#include <osmocom/mgcp/mgcp_common.h>
|
char *save;
|
||||||
#include <osmocom/mgcp/mgcp_codec.h>
|
|
||||||
|
|
||||||
enum mgcp_verb {
|
|
||||||
MGCP_VERB_CRCX,
|
|
||||||
MGCP_VERB_MDCX,
|
|
||||||
MGCP_VERB_DLCX,
|
|
||||||
MGCP_VERB_AUEP,
|
|
||||||
MGCP_VERB_RQNT,
|
|
||||||
MGCP_VERB_RSIP,
|
|
||||||
};
|
};
|
||||||
extern const struct value_string mgcp_verb_names[];
|
|
||||||
static inline const char *mgcp_verb_name(enum mgcp_verb val)
|
|
||||||
{ return get_value_string(mgcp_verb_names, val); }
|
|
||||||
|
|
||||||
|
|
||||||
#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
|
|
||||||
#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
|
|
||||||
#define MGCP_PARSE_SDP_RTP_PORT_UNSET (0)
|
|
||||||
|
|
||||||
struct mgcp_parse_sdp {
|
|
||||||
int ptime;
|
|
||||||
int maxptime;
|
|
||||||
int rtp_port;
|
|
||||||
struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */
|
|
||||||
struct mgcp_rtp_codecset cset;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
|
|
||||||
{
|
|
||||||
sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET;
|
|
||||||
sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET;
|
|
||||||
sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET;
|
|
||||||
sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC };
|
|
||||||
mgcp_codecset_reset(&sdp->cset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Local connection options */
|
/* Local connection options */
|
||||||
struct mgcp_lco {
|
struct mgcp_lco {
|
||||||
bool present;
|
char *string;
|
||||||
char *codec; /* talloc-allocated to some parent */
|
char *codec;
|
||||||
int pkt_period_min; /* time in ms */
|
int pkt_period_min; /* time in ms */
|
||||||
int pkt_period_max; /* time in ms */
|
int pkt_period_max; /* time in ms */
|
||||||
};
|
};
|
||||||
static inline void mgcp_lco_init(struct mgcp_lco *lco)
|
|
||||||
{
|
|
||||||
*lco = (struct mgcp_lco){};
|
|
||||||
}
|
|
||||||
char *get_lco_identifier(const char *options);
|
|
||||||
int check_local_cx_options(void *ctx, const char *options);
|
|
||||||
|
|
||||||
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2)
|
|
||||||
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1)
|
|
||||||
|
|
||||||
struct mgcp_parse_hdr_pars {
|
|
||||||
const char *lco_string;
|
|
||||||
struct mgcp_lco lco;
|
|
||||||
const char *callid;
|
|
||||||
const char *connid;
|
|
||||||
enum mgcp_connection_mode mode;
|
|
||||||
int remote_osmux_cid;
|
|
||||||
bool have_sdp;
|
|
||||||
/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
|
|
||||||
uint32_t x_osmo_ign;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
|
|
||||||
{
|
|
||||||
hpars->lco_string = NULL;
|
|
||||||
mgcp_lco_init(&hpars->lco);
|
|
||||||
hpars->callid = NULL;
|
|
||||||
hpars->connid = NULL;
|
|
||||||
hpars->mode = MGCP_CONN_NONE;
|
|
||||||
hpars->remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
|
|
||||||
hpars->have_sdp = false;
|
|
||||||
hpars->x_osmo_ign = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Internal structure while parsing a request */
|
|
||||||
struct mgcp_request_data;
|
|
||||||
struct mgcp_parse_data {
|
|
||||||
struct mgcp_request_data *rq; /* backpointer to request context */
|
|
||||||
char *save;
|
|
||||||
/* MGCP Header: */
|
|
||||||
char *epname;
|
|
||||||
char *trans;
|
|
||||||
struct mgcp_parse_hdr_pars hpars;
|
|
||||||
/* MGCP Body: */
|
|
||||||
struct mgcp_parse_sdp sdp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Request data passed to the request handler */
|
|
||||||
struct mgcp_request_data {
|
|
||||||
enum mgcp_verb verb;
|
|
||||||
/* Verb string (e.g. "MDCX") */
|
|
||||||
char name[4+1];
|
|
||||||
|
|
||||||
/* Global MGW config */
|
|
||||||
struct mgcp_config *cfg;
|
|
||||||
|
|
||||||
/* parsing results from the MGCP header (trans id, endpoint name ...) */
|
|
||||||
struct mgcp_parse_data *pdata;
|
|
||||||
|
|
||||||
/* pointer to endpoint resource (may be NULL for wildcarded requests) */
|
|
||||||
struct mgcp_endpoint *endp;
|
|
||||||
|
|
||||||
/* pointer to trunk resource */
|
|
||||||
struct mgcp_trunk *trunk;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
char *mgcp_debug_get_last_endpoint_name(void);
|
char *mgcp_debug_get_last_endpoint_name(void);
|
||||||
|
|
||||||
|
char *get_lco_identifier(const char *options);
|
||||||
|
int check_local_cx_options(void *ctx, const char *options);
|
||||||
|
|
||||||
struct mgcp_rtp_end;
|
struct mgcp_rtp_end;
|
||||||
struct mgcp_endpoint;
|
struct mgcp_endpoint;
|
||||||
|
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||||
|
struct mgcp_rtp_end *rtp);
|
||||||
|
|
||||||
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
|
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
|
||||||
const struct mgcp_rtp_end *rtp);
|
const struct mgcp_rtp_end *rtp);
|
||||||
|
|
||||||
extern const struct value_string mgcp_connection_mode_strs[];
|
|
||||||
static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
|
|
||||||
{
|
|
||||||
return get_value_string(mgcp_connection_mode_strs, mode);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ enum {
|
|||||||
MGCP_MDCX_FAIL_INVALID_MODE,
|
MGCP_MDCX_FAIL_INVALID_MODE,
|
||||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
||||||
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||||
MGCP_MDCX_FAIL_BIND_PORT,
|
MGCP_MDCX_FAIL_START_RTP,
|
||||||
MGCP_MDCX_FAIL_AVAIL,
|
MGCP_MDCX_FAIL_AVAIL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/socket.h>
|
|
||||||
#include <osmocom/core/osmo_io.h>
|
|
||||||
|
|
||||||
#include <osmocom/mgcp/mgcp.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_codec.h>
|
|
||||||
|
|
||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
|
||||||
struct mgcp_rtp_end {
|
|
||||||
struct mgcp_conn_rtp *conn_rtp; /* backpointer */
|
|
||||||
/* remote IP address of the RTP socket */
|
|
||||||
struct osmo_sockaddr addr;
|
|
||||||
|
|
||||||
/* in network byte order */
|
|
||||||
uint16_t rtcp_port;
|
|
||||||
|
|
||||||
struct mgcp_rtp_codecset cset;
|
|
||||||
|
|
||||||
/* per endpoint data */
|
|
||||||
int frames_per_packet;
|
|
||||||
uint32_t packet_duration_ms;
|
|
||||||
int maximum_packet_time; /* -1: not set */
|
|
||||||
/* are we transmitting packets (true) or dropping (false) outbound packets */
|
|
||||||
bool output_enabled;
|
|
||||||
/* FIXME: This parameter can be set + printed, but is nowhere used! */
|
|
||||||
int force_output_ptime;
|
|
||||||
|
|
||||||
/* RTP patching */
|
|
||||||
bool force_constant_ssrc;
|
|
||||||
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
|
|
||||||
int force_aligned_timing;
|
|
||||||
bool rfc5993_hr_convert;
|
|
||||||
|
|
||||||
/* Each end has a separate socket for RTP and RTCP */
|
|
||||||
struct osmo_io_fd *rtp;
|
|
||||||
struct osmo_io_fd *rtcp;
|
|
||||||
|
|
||||||
/* local UDP port number of the RTP socket; RTCP is +1 */
|
|
||||||
int local_port;
|
|
||||||
/* where the endpoint RTP connection binds to, set during CRCX and
|
|
||||||
* possibly updated during MDCX */
|
|
||||||
char local_addr[INET6_ADDRSTRLEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp);
|
|
||||||
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end);
|
|
||||||
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms);
|
|
||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
|
|
||||||
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end);
|
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct mgcp_parse_data;
|
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||||
|
struct mgcp_conn_rtp *conn,
|
||||||
int mgcp_parse_sdp_data(struct mgcp_parse_data *p);
|
struct mgcp_parse_data *p);
|
||||||
|
|
||||||
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||||
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
|
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
#include <osmocom/gsm/i460_mux.h>
|
#include <osmocom/gsm/i460_mux.h>
|
||||||
#include <osmocom/abis/e1_input.h>
|
#include <osmocom/abis/e1_input.h>
|
||||||
#include <osmocom/mgcp/mgcp_conn.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_network.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_ratectr.h>
|
#include <osmocom/mgcp/mgcp_ratectr.h>
|
||||||
|
|
||||||
|
|
||||||
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
|
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
|
||||||
LOGP(cat, level, "trunk:%u " fmt, \
|
LOGP(cat, level, "trunk:%u " fmt, \
|
||||||
trunk ? trunk->trunk_nr : 0, \
|
trunk ? trunk->trunk_nr : 0, \
|
||||||
@@ -28,6 +27,7 @@ struct mgcp_trunk {
|
|||||||
unsigned int trunk_nr;
|
unsigned int trunk_nr;
|
||||||
enum mgcp_trunk_type trunk_type;
|
enum mgcp_trunk_type trunk_type;
|
||||||
|
|
||||||
|
char *audio_fmtp_extra;
|
||||||
int audio_send_ptime;
|
int audio_send_ptime;
|
||||||
int audio_send_name;
|
int audio_send_name;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ struct mgcp_trunk {
|
|||||||
int keepalive_interval;
|
int keepalive_interval;
|
||||||
|
|
||||||
/* RTP patching */
|
/* RTP patching */
|
||||||
bool force_constant_ssrc;
|
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||||
int force_aligned_timing;
|
int force_aligned_timing;
|
||||||
bool rfc5993_hr_convert;
|
bool rfc5993_hr_convert;
|
||||||
|
|
||||||
@@ -79,7 +79,6 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
|
|||||||
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
|
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
|
||||||
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
|
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
|
||||||
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
|
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
|
||||||
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp);
|
|
||||||
|
|
||||||
/* The virtual trunk is always created on trunk id 0 for historical reasons,
|
/* The virtual trunk is always created on trunk id 0 for historical reasons,
|
||||||
* use this define constant as ID when allocating a virtual trunk. Other
|
* use this define constant as ID when allocating a virtual trunk. Other
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
BUILT_SOURCES = \
|
BUILT_SOURCES = \
|
||||||
mgcp_common.h \
|
mgcp_common.h \
|
||||||
version.h \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
@@ -12,20 +11,4 @@ mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
|
|||||||
echo -e "/*\n\n DO NOT EDIT THIS FILE!\n THIS IS OVERWRITTEN DURING BUILD\n This is an automatic copy of <osmocom/mgcp/mgcp_common.h>\n\n */" > mgcp_common.h
|
echo -e "/*\n\n DO NOT EDIT THIS FILE!\n THIS IS OVERWRITTEN DURING BUILD\n This is an automatic copy of <osmocom/mgcp/mgcp_common.h>\n\n */" > mgcp_common.h
|
||||||
cat $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h >> mgcp_common.h
|
cat $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h >> mgcp_common.h
|
||||||
|
|
||||||
version.h: version.h.tpl
|
CLEANFILES = mgcp_common.h
|
||||||
$(AM_V_GEN)$(MKDIR_P) $(dir $@)
|
|
||||||
$(AM_V_GEN)sed \
|
|
||||||
-e "s/{{VERSION}}/$$(echo '@VERSION@' | cut -d. -f1-3)/g" \
|
|
||||||
-e "s/{{VERSION_MAJOR}}/$$(echo '@VERSION@' | cut -d. -f1)/g" \
|
|
||||||
-e "s/{{VERSION_MINOR}}/$$(echo '@VERSION@' | cut -d. -f2)/g" \
|
|
||||||
-e "s/{{VERSION_PATCH}}/$$(echo '@VERSION@' | cut -d. -f3)/g" \
|
|
||||||
$< > $@
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
version.h.tpl \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
CLEANFILES = \
|
|
||||||
mgcp_common.h \
|
|
||||||
version.h \
|
|
||||||
$(NULL)
|
|
||||||
|
|||||||
@@ -79,7 +79,27 @@ struct ptmap {
|
|||||||
unsigned int pt;
|
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 {
|
enum mgcp_verb {
|
||||||
MGCP_VERB_CRCX,
|
MGCP_VERB_CRCX,
|
||||||
@@ -89,6 +109,37 @@ enum mgcp_verb {
|
|||||||
MGCP_VERB_RSIP,
|
MGCP_VERB_RSIP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
|
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!)");
|
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!)");
|
||||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
|
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
|
||||||
@@ -110,8 +161,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,
|
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);
|
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;
|
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[];
|
extern const struct value_string mgcp_client_connection_mode_strs[];
|
||||||
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
|
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
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_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_name(const struct osmo_mgcpc_ep_ci *ci);
|
||||||
const char *osmo_mgcpc_ep_ci_id(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);
|
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ struct mgcp_conn_peer {
|
|||||||
/*! RTP packetization interval (optional) */
|
/*! RTP packetization interval (optional) */
|
||||||
unsigned int ptime;
|
unsigned int ptime;
|
||||||
|
|
||||||
/*! Deprecated. Use only ptmap[].codec in new code. */
|
/*! RTP codec list (optional) */
|
||||||
enum mgcp_codecs codecs[MGCP_MAX_CODECS]
|
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
|
||||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
|
|
||||||
unsigned int codecs_len
|
/*! Number of codecs in RTP codec list (optional) */
|
||||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
|
unsigned int codecs_len;
|
||||||
|
|
||||||
/*! RTP payload type map (optional, only needed when payload types are
|
/*! RTP payload type map (optional, only needed when payload types are
|
||||||
* used that differ from what IANA/3GPP defines) */
|
* 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,
|
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)
|
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);
|
||||||
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);
|
||||||
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");
|
|
||||||
|
|
||||||
const char *mgcp_conn_get_ci(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");
|
|
||||||
struct mgcp_client *mgcp_conn_get_client(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);
|
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <osmocom/core/osmo_io.h>
|
#include <osmocom/core/write_queue.h>
|
||||||
#include <osmocom/core/timer.h>
|
#include <osmocom/core/timer.h>
|
||||||
|
|
||||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
|
||||||
|
|
||||||
#define MSGB_CB_MGCP_TRANS_ID 0
|
#define MSGB_CB_MGCP_TRANS_ID 0
|
||||||
|
|
||||||
/* Struct that holds one endpoint name */
|
/* Struct that holds one endpoint name */
|
||||||
@@ -15,7 +13,7 @@ struct reset_ep {
|
|||||||
|
|
||||||
struct mgcp_client {
|
struct mgcp_client {
|
||||||
struct mgcp_client_conf actual;
|
struct mgcp_client_conf actual;
|
||||||
struct osmo_io_fd *iofd;
|
struct osmo_wqueue wq;
|
||||||
mgcp_trans_id_t next_trans_id;
|
mgcp_trans_id_t next_trans_id;
|
||||||
struct llist_head responses_pending;
|
struct llist_head responses_pending;
|
||||||
struct mgcp_client_pool_member *pool_member;
|
struct mgcp_client_pool_member *pool_member;
|
||||||
@@ -24,30 +22,6 @@ struct mgcp_client {
|
|||||||
bool conn_up;
|
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_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 mgcp_response_pending {
|
||||||
struct llist_head entry;
|
struct llist_head entry;
|
||||||
|
|
||||||
@@ -63,41 +37,3 @@ struct mgcp_response_pending * mgcp_client_pending_add(
|
|||||||
mgcp_trans_id_t trans_id,
|
mgcp_trans_id_t trans_id,
|
||||||
mgcp_response_cb_t response_cb,
|
mgcp_response_cb_t response_cb,
|
||||||
void *priv);
|
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);
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <osmocom/vty/vty.h>
|
|
||||||
|
|
||||||
struct mgcp_client;
|
struct mgcp_client;
|
||||||
struct mgcp_client_pool;
|
struct mgcp_client_pool;
|
||||||
struct mgcp_client_pool_member;
|
struct mgcp_client_pool_member;
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION {{VERSION}}
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION_STR "{{VERSION}}"
|
|
||||||
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION_MAJOR {{VERSION_MAJOR}}
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION_MINOR {{VERSION_MINOR}}
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION_PATCH {{VERSION_PATCH}}
|
|
||||||
|
|
||||||
#define LIBOSMO_MGCP_CLIENT_VERSION_GREATER_EQUAL(major, minor, patch) \
|
|
||||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR > (major) || \
|
|
||||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR == (major) && \
|
|
||||||
LIBOSMO_MGCP_CLIENT_VERSION_MINOR > (minor)) || \
|
|
||||||
(LIBOSMO_MGCP_CLIENT_VERSION_MAJOR == (major) && \
|
|
||||||
LIBOSMO_MGCP_CLIENT_VERSION_MINOR == (minor) && \
|
|
||||||
LIBOSMO_MGCP_CLIENT_VERSION_PATCH >= (patch)))
|
|
||||||
@@ -19,7 +19,7 @@ AM_LDFLAGS = \
|
|||||||
|
|
||||||
# This is not at all related to the release version, but a range of supported
|
# 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!
|
# API versions. Read TODO_RELEASE in the source tree's root!
|
||||||
MGCP_CLIENT_LIBVERSION=14:1:0
|
MGCP_CLIENT_LIBVERSION=11:0:0
|
||||||
|
|
||||||
lib_LTLIBRARIES = \
|
lib_LTLIBRARIES = \
|
||||||
libosmo-mgcp-client.la \
|
libosmo-mgcp-client.la \
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
|
|||||||
char *pt_str;
|
char *pt_str;
|
||||||
char *pt_end;
|
char *pt_end;
|
||||||
unsigned long int pt;
|
unsigned long int pt;
|
||||||
unsigned int ptmap_len;
|
unsigned int count = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Extract port information */
|
/* Extract port information */
|
||||||
@@ -316,58 +316,40 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
|
|||||||
if (!line)
|
if (!line)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
/* Clear any previous entries before writing over r->ptmap */
|
|
||||||
r->ptmap_len = 0;
|
|
||||||
/* Keep a local ptmap_len to show only the full list after parsing succeeded in whole. */
|
|
||||||
ptmap_len = 0;
|
|
||||||
|
|
||||||
pt_str = strtok(line, " ");
|
pt_str = strtok(line, " ");
|
||||||
while (1) {
|
while (1) {
|
||||||
|
/* Do not allow excessive payload types */
|
||||||
|
if (count > ARRAY_SIZE(r->codecs))
|
||||||
|
goto response_parse_failure_pt;
|
||||||
|
|
||||||
pt_str = strtok(NULL, " ");
|
pt_str = strtok(NULL, " ");
|
||||||
if (!pt_str)
|
if (!pt_str)
|
||||||
break;
|
break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
pt = strtoul(pt_str, &pt_end, 0);
|
pt = strtoul(pt_str, &pt_end, 0);
|
||||||
if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
|
if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
|
||||||
pt_str == pt_end) {
|
pt_str == pt_end)
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "SDP: cannot parse payload type number from '%s'\n", pt_str);
|
|
||||||
goto response_parse_failure_pt;
|
goto response_parse_failure_pt;
|
||||||
}
|
|
||||||
|
|
||||||
/* PT is 7 bit field, higher values not allowed */
|
if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
|
||||||
if (pt >> 7) {
|
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "SDP: payload type number out of range: %lu > 127\n", pt);
|
|
||||||
goto response_parse_failure_pt;
|
goto response_parse_failure_pt;
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not allow duplicate payload types */
|
/* Do not allow duplicate payload types */
|
||||||
for (i = 0; i < ptmap_len; i++) {
|
for (i = 0; i < count; i++)
|
||||||
if (r->ptmap[i].pt == pt) {
|
if (r->codecs[i] == pt)
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "SDP: payload type number %lu listed twice\n", pt);
|
|
||||||
goto response_parse_failure_pt;
|
goto response_parse_failure_pt;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not allow excessive payload types */
|
/* Note: The payload type we store may not necessarly match
|
||||||
if (ptmap_len >= ARRAY_SIZE(r->ptmap)) {
|
* the codec types we have defined in enum mgcp_codecs. To
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
* ensure that the end result only contains codec types which
|
||||||
"SDP: can parse only up to %zu payload type numbers\n", ARRAY_SIZE(r->ptmap));
|
* match enum mgcp_codecs, we will go through afterwards and
|
||||||
goto response_parse_failure_pt;
|
* remap the affected entries with the inrofmation we learn
|
||||||
}
|
* from rtpmap */
|
||||||
|
r->codecs[count] = pt;
|
||||||
/* Some payload type numbers imply a specific codec. For those, using the PT number as enum mgcp_codecs
|
count++;
|
||||||
* yields the correct result. If no more specific information on the codec follows in "a=rtpmap:N"
|
|
||||||
* lines, then this default number takes over. This only applies for PT below the dynamic range (<96). */
|
|
||||||
if (pt < 96)
|
|
||||||
r->ptmap[ptmap_len].codec = pt;
|
|
||||||
else
|
|
||||||
r->ptmap[ptmap_len].codec = -1;
|
|
||||||
r->ptmap[ptmap_len].pt = pt;
|
|
||||||
ptmap_len++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parsing succeeded, publish all entries. */
|
r->codecs_len = count;
|
||||||
r->ptmap_len = ptmap_len;
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -383,11 +365,10 @@ response_parse_failure_pt:
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse an 'a=...' parameter */
|
/* Parse a line like "m=audio 16002 RTP/AVP 98", extract port and payload types */
|
||||||
static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *line)
|
static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *line)
|
||||||
{
|
{
|
||||||
unsigned int pt;
|
unsigned int pt;
|
||||||
unsigned int i;
|
|
||||||
char codec_resp[64];
|
char codec_resp[64];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -406,39 +387,18 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
|
|||||||
"Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
|
"Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
|
||||||
|
LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
rc = map_str_to_codec(codec_resp);
|
rc = map_str_to_codec(codec_resp);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
LOGP(DLMGCP, LOGL_ERROR,
|
||||||
"Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
|
"Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
r->ptmap[r->ptmap_len].pt = pt;
|
||||||
/* Earlier, a line like "m=audio 16002 RTP/AVP 98 112 3" established the desired order of payloads, now
|
r->ptmap[r->ptmap_len].codec = rc;
|
||||||
* enrich it with actual codec information provided by "a=rtpmap:..." entries.
|
|
||||||
* For each, find the entry with the right pt number and add the info there. */
|
|
||||||
|
|
||||||
for (i = 0; i < r->ptmap_len; i++) {
|
|
||||||
if (r->ptmap[i].pt != pt)
|
|
||||||
continue;
|
|
||||||
r->ptmap[i].codec = rc;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No entry was found. This is an error in the MGCP protocol, but let's just add another entry
|
|
||||||
* anyway, to not make it look like it was never there. */
|
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
|
||||||
"error in MGCP message: 'a=rtpmap:%u' has no matching entry in 'm=audio ... %u'\n",
|
|
||||||
pt, pt);
|
|
||||||
if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
|
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
|
||||||
"cannot parse all codecs: can only store up to %zu rtpmap entries.\n",
|
|
||||||
ARRAY_SIZE(r->ptmap));
|
|
||||||
return -ENOSPC;
|
|
||||||
}
|
|
||||||
r->ptmap[r->ptmap_len] = (struct ptmap){
|
|
||||||
.pt = pt,
|
|
||||||
.codec = rc,
|
|
||||||
};
|
|
||||||
r->ptmap_len++;
|
r->ptmap_len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +508,7 @@ int mgcp_response_parse_params(struct mgcp_response *r)
|
|||||||
int rc;
|
int rc;
|
||||||
char *data;
|
char *data;
|
||||||
char *data_ptr;
|
char *data_ptr;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Since this functions performs a destructive parsing, we create a
|
/* Since this functions performs a destructive parsing, we create a
|
||||||
* local copy of the body data */
|
* local copy of the body data */
|
||||||
@@ -592,6 +553,10 @@ int mgcp_response_parse_params(struct mgcp_response *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See also note in mgcp_parse_audio_port_pt() */
|
||||||
|
for (i = 0; i < r->codecs_len; i++)
|
||||||
|
r->codecs[i] = map_pt_to_codec(r->ptmap, r->ptmap_len, r->codecs[i]);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
exit:
|
exit:
|
||||||
talloc_free(data);
|
talloc_free(data);
|
||||||
@@ -728,7 +693,7 @@ static struct mgcp_response_pending *mgcp_client_response_pending_get(
|
|||||||
/* Feed an MGCP message into the receive processing.
|
/* Feed an MGCP message into the receive processing.
|
||||||
* Parse the head and call any callback registered for the transaction id found
|
* Parse the head and call any callback registered for the transaction id found
|
||||||
* in the MGCP message. This is normally called directly from the internal
|
* in the MGCP message. This is normally called directly from the internal
|
||||||
* mgcp_read_cb that reads from the socket connected to the MGCP gateway. This
|
* mgcp_do_read that reads from the socket connected to the MGCP gateway. This
|
||||||
* function is published mainly to be able to feed data from the test suite.
|
* function is published mainly to be able to feed data from the test suite.
|
||||||
*/
|
*/
|
||||||
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
|
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
|
||||||
@@ -781,58 +746,54 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
|
static int mgcp_do_read(struct osmo_fd *fd)
|
||||||
{
|
|
||||||
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
|
|
||||||
|
|
||||||
if (res <= 0) {
|
|
||||||
char errbuf[128] = "";
|
|
||||||
strerror_r(-res, errbuf, sizeof(errbuf));
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
|
|
||||||
osmo_iofd_get_name(iofd), res, errbuf);
|
|
||||||
|
|
||||||
msgb_free(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->l2h = msg->head;
|
|
||||||
mgcp_client_rx(mgcp, msg);
|
|
||||||
talloc_free(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mgcp_do_write(struct mgcp_client *mgcp, struct msgb *msg)
|
|
||||||
{
|
{
|
||||||
|
struct mgcp_client *mgcp = fd->data;
|
||||||
|
struct msgb *msg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
|
||||||
|
if (!msg) {
|
||||||
|
LOGPMGW(mgcp, LOGL_ERROR, "Failed to allocate MGCP message.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = read(fd->fd, msg->data, 4096 - 128);
|
||||||
|
if (ret <= 0) {
|
||||||
|
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
|
||||||
|
osmo_sock_get_name2(fd->fd), errno, strerror(errno));
|
||||||
|
|
||||||
|
msgb_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->l2h = msgb_put(msg, ret);
|
||||||
|
ret = mgcp_client_rx(mgcp, msg);
|
||||||
|
talloc_free(msg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct mgcp_client *mgcp = fd->data;
|
||||||
|
|
||||||
LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
|
LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
|
||||||
osmo_iofd_get_name(mgcp->iofd), msg->len,
|
osmo_sock_get_name2(fd->fd), msg->len,
|
||||||
osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
|
osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
|
||||||
|
|
||||||
ret = osmo_iofd_write_msgb(mgcp->iofd, msg);
|
ret = write(fd->fd, msg->data, msg->len);
|
||||||
if (ret < 0)
|
if (OSMO_UNLIKELY(ret != msg->len))
|
||||||
msgb_free(msg);
|
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
|
||||||
|
osmo_sock_get_name2(fd->fd), errno, strerror(errno),
|
||||||
|
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
|
||||||
|
|
||||||
/* Re-arm the keepalive Tx timer: */
|
/* Re-arm the keepalive Tx timer: */
|
||||||
if (mgcp->actual.keepalive.req_interval_sec > 0)
|
if (mgcp->actual.keepalive.req_interval_sec > 0)
|
||||||
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
|
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
|
|
||||||
{
|
|
||||||
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
|
|
||||||
|
|
||||||
if (OSMO_UNLIKELY(res != msg->len)) {
|
|
||||||
char errbuf[128] = "";
|
|
||||||
strerror_r(-res, errbuf, sizeof(errbuf));
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
|
|
||||||
osmo_iofd_get_name(mgcp->iofd), res, errbuf,
|
|
||||||
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
|
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
|
||||||
{
|
{
|
||||||
static char endpoint[MGCP_ENDPOINT_MAXLEN];
|
static char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||||
@@ -864,10 +825,6 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
|
|||||||
};
|
};
|
||||||
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
|
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
|
||||||
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
|
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
|
||||||
if (!msgb_dlcx) {
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
|
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,10 +838,6 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
|
|||||||
};
|
};
|
||||||
OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
|
OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
|
||||||
msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
|
msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
|
||||||
if (!msgb_auep) {
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
|
mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,6 +905,11 @@ struct mgcp_client *mgcp_client_init(void *ctx,
|
|||||||
if (conf->description)
|
if (conf->description)
|
||||||
mgcp->actual.description = talloc_strdup(mgcp, conf->description);
|
mgcp->actual.description = talloc_strdup(mgcp, conf->description);
|
||||||
|
|
||||||
|
osmo_wqueue_init(&mgcp->wq, 1024);
|
||||||
|
mgcp->wq.read_cb = mgcp_do_read;
|
||||||
|
mgcp->wq.write_cb = mgcp_do_write;
|
||||||
|
osmo_fd_setup(&mgcp->wq.bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
|
||||||
|
|
||||||
memcpy(&mgcp->actual.keepalive, &conf->keepalive, sizeof(conf->keepalive));
|
memcpy(&mgcp->actual.keepalive, &conf->keepalive, sizeof(conf->keepalive));
|
||||||
osmo_timer_setup(&mgcp->keepalive_tx_timer, mgcp_client_keepalive_tx_timer_cb, mgcp);
|
osmo_timer_setup(&mgcp->keepalive_tx_timer, mgcp_client_keepalive_tx_timer_cb, mgcp);
|
||||||
osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
|
osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
|
||||||
@@ -959,11 +917,6 @@ struct mgcp_client *mgcp_client_init(void *ctx,
|
|||||||
return mgcp;
|
return mgcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct osmo_io_ops mgcp_clnt_ioops = {
|
|
||||||
.read_cb = mgcp_read_cb,
|
|
||||||
.write_cb = mgcp_write_cb,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*! Initialize client connection (opens socket)
|
/*! Initialize client connection (opens socket)
|
||||||
* \param[in,out] mgcp MGCP client descriptor.
|
* \param[in,out] mgcp MGCP client descriptor.
|
||||||
* \returns 0 on success, -EINVAL on error. */
|
* \returns 0 on success, -EINVAL on error. */
|
||||||
@@ -979,28 +932,19 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
|
rc = osmo_sock_init2_ofd(&mgcp->wq.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
|
||||||
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
|
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
|
||||||
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
|
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGPMGW(mgcp, LOGL_FATAL,
|
LOGPMGW(mgcp, LOGL_FATAL,
|
||||||
"Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
|
"Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
|
||||||
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
|
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
|
||||||
mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
|
mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto error_free;
|
goto error_close_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
mgcp->iofd = osmo_iofd_setup(mgcp, rc, osmo_sock_get_name2(rc), OSMO_IO_FD_MODE_READ_WRITE,
|
LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(mgcp->wq.bfd.fd));
|
||||||
&mgcp_clnt_ioops, mgcp);
|
|
||||||
if (!mgcp->iofd)
|
|
||||||
goto error_close_fd;
|
|
||||||
|
|
||||||
LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_iofd_get_name(mgcp->iofd));
|
|
||||||
|
|
||||||
osmo_iofd_register(mgcp->iofd, -1);
|
|
||||||
osmo_iofd_set_alloc_info(mgcp->iofd, 4096, 128);
|
|
||||||
osmo_iofd_set_txqueue_max_length(mgcp->iofd, 1024);
|
|
||||||
|
|
||||||
/* If configured, send a DLCX message to the endpoints that are configured to
|
/* If configured, send a DLCX message to the endpoints that are configured to
|
||||||
* be reset on startup. Usually this is a wildcarded endpoint. */
|
* be reset on startup. Usually this is a wildcarded endpoint. */
|
||||||
@@ -1026,10 +970,9 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
|
|||||||
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
|
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_close_fd:
|
error_close_fd:
|
||||||
close(rc);
|
close(mgcp->wq.bfd.fd);
|
||||||
error_free:
|
mgcp->wq.bfd.fd = -1;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1046,6 +989,8 @@ int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
|
|||||||
* \returns 0 on success, -EINVAL on error. */
|
* \returns 0 on success, -EINVAL on error. */
|
||||||
void mgcp_client_disconnect(struct mgcp_client *mgcp)
|
void mgcp_client_disconnect(struct mgcp_client *mgcp)
|
||||||
{
|
{
|
||||||
|
struct osmo_wqueue *wq;
|
||||||
|
|
||||||
if (!mgcp) {
|
if (!mgcp) {
|
||||||
LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
|
LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
|
||||||
return;
|
return;
|
||||||
@@ -1056,10 +1001,13 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
|
|||||||
osmo_timer_del(&mgcp->keepalive_tx_timer);
|
osmo_timer_del(&mgcp->keepalive_tx_timer);
|
||||||
mgcp->conn_up = false;
|
mgcp->conn_up = false;
|
||||||
|
|
||||||
osmo_iofd_txqueue_clear(mgcp->iofd);
|
wq = &mgcp->wq;
|
||||||
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd));
|
osmo_wqueue_clear(wq);
|
||||||
osmo_iofd_free(mgcp->iofd);
|
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
|
||||||
mgcp->iofd = NULL;
|
if (osmo_fd_is_registered(&wq->bfd))
|
||||||
|
osmo_fd_unregister(&wq->bfd);
|
||||||
|
close(wq->bfd.fd);
|
||||||
|
wq->bfd.fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get the IP-Aaddress of the associated MGW as string.
|
/*! Get the IP-Aaddress of the associated MGW as string.
|
||||||
@@ -1213,9 +1161,10 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
|
|||||||
goto mgcp_tx_error;
|
goto mgcp_tx_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = mgcp_do_write(mgcp, msg);
|
rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
|
LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
|
||||||
|
msgb_free(msg);
|
||||||
goto mgcp_tx_error;
|
goto mgcp_tx_error;
|
||||||
} else
|
} else
|
||||||
LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
|
LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
|
||||||
@@ -1284,6 +1233,7 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
const char *codec;
|
const char *codec;
|
||||||
|
unsigned int pt;
|
||||||
|
|
||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
|
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
|
||||||
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
|
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
|
||||||
@@ -1297,10 +1247,11 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
|
|||||||
if (mgcp_msg->ptime)
|
if (mgcp_msg->ptime)
|
||||||
MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
|
MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
|
||||||
|
|
||||||
if (mgcp_msg->ptmap_len) {
|
if (mgcp_msg->codecs_len) {
|
||||||
MSGB_PRINTF_OR_RET(" a:");
|
MSGB_PRINTF_OR_RET(" a:");
|
||||||
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
|
for (i = 0; i < mgcp_msg->codecs_len; i++) {
|
||||||
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
|
pt = mgcp_msg->codecs[i];
|
||||||
|
codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
|
||||||
|
|
||||||
/* Note: Use codec descriptors from enum mgcp_codecs
|
/* Note: Use codec descriptors from enum mgcp_codecs
|
||||||
* in mgcp_client only! */
|
* in mgcp_client only! */
|
||||||
@@ -1308,7 +1259,7 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
|
MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
|
||||||
if (i < mgcp_msg->ptmap_len - 1)
|
if (i < mgcp_msg->codecs_len - 1)
|
||||||
MSGB_PRINTF_OR_RET(";");
|
MSGB_PRINTF_OR_RET(";");
|
||||||
}
|
}
|
||||||
MSGB_PRINTF_OR_RET(",");
|
MSGB_PRINTF_OR_RET(",");
|
||||||
@@ -1320,36 +1271,6 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
|
|||||||
#undef MSGB_PRINTF_OR_RET
|
#undef MSGB_PRINTF_OR_RET
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function to obtain local IP address used in MGCP towards MGW,
|
|
||||||
* in string format, to fill the SDP "Origin" ("o=") field.
|
|
||||||
* return 0 on success, negative on error.
|
|
||||||
*/
|
|
||||||
static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* Try to get the socket local IP address if available: */
|
|
||||||
if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) {
|
|
||||||
if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0)
|
|
||||||
return 0;
|
|
||||||
/* else: continue below */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If MGCP local address was explicitly specified in config, use it: */
|
|
||||||
if (mgcp->actual.local_addr) {
|
|
||||||
osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Guess our local address based on system routing towards MGW: */
|
|
||||||
OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN);
|
|
||||||
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
|
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
|
||||||
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
|
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
|
||||||
{
|
{
|
||||||
@@ -1358,8 +1279,6 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
|
|||||||
int local_ip_family, audio_ip_family;
|
int local_ip_family, audio_ip_family;
|
||||||
const char *codec;
|
const char *codec;
|
||||||
unsigned int pt;
|
unsigned int pt;
|
||||||
uint16_t audio_port;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
|
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
|
||||||
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
|
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
|
||||||
@@ -1375,12 +1294,17 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
|
|||||||
MSGB_PRINTF_OR_RET("v=0\r\n");
|
MSGB_PRINTF_OR_RET("v=0\r\n");
|
||||||
|
|
||||||
/* Determine local IP-Address */
|
/* Determine local IP-Address */
|
||||||
rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip));
|
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
|
||||||
if (rc < 0)
|
LOGPMGW(mgcp, LOGL_ERROR,
|
||||||
return rc;
|
"Could not determine local IP-Address!\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
local_ip_family = osmo_ip_str_type(local_ip);
|
local_ip_family = osmo_ip_str_type(local_ip);
|
||||||
if (local_ip_family == AF_UNSPEC)
|
if (local_ip_family == AF_UNSPEC)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
|
||||||
|
if (audio_ip_family == AF_UNSPEC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* Add owner/creator (SDP) */
|
/* Add owner/creator (SDP) */
|
||||||
MSGB_PRINTF_OR_RET("o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
|
MSGB_PRINTF_OR_RET("o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
|
||||||
@@ -1390,79 +1314,56 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
|
|||||||
/* Add session name (none) */
|
/* Add session name (none) */
|
||||||
MSGB_PRINTF_OR_RET("s=-\r\n");
|
MSGB_PRINTF_OR_RET("s=-\r\n");
|
||||||
|
|
||||||
/* Add RTP address */
|
/* Add RTP address and port */
|
||||||
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP) {
|
if (mgcp_msg->audio_port == 0) {
|
||||||
audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
|
LOGPMGW(mgcp, LOGL_ERROR,
|
||||||
if (audio_ip_family == AF_UNSPEC)
|
"Invalid port number, can not generate MGCP message\n");
|
||||||
return -EINVAL;
|
msgb_free(msg);
|
||||||
if (strlen(mgcp_msg->audio_ip) <= 0) {
|
return -EINVAL;
|
||||||
LOGPMGW(mgcp, LOGL_ERROR,
|
|
||||||
"Empty ip address, can not generate MGCP message\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
MSGB_PRINTF_OR_RET("c=IN IP%c %s\r\n",
|
|
||||||
audio_ip_family == AF_INET6 ? '6' : '4',
|
|
||||||
mgcp_msg->audio_ip);
|
|
||||||
}
|
}
|
||||||
|
if (strlen(mgcp_msg->audio_ip) <= 0) {
|
||||||
|
LOGPMGW(mgcp, LOGL_ERROR,
|
||||||
|
"Empty ip address, can not generate MGCP message\n");
|
||||||
|
msgb_free(msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
MSGB_PRINTF_OR_RET("c=IN IP%c %s\r\n",
|
||||||
|
audio_ip_family == AF_INET6 ? '6' : '4',
|
||||||
|
mgcp_msg->audio_ip);
|
||||||
|
|
||||||
/* Add time description, active time (SDP) */
|
/* Add time description, active time (SDP) */
|
||||||
MSGB_PRINTF_OR_RET("t=0 0\r\n");
|
MSGB_PRINTF_OR_RET("t=0 0\r\n");
|
||||||
|
|
||||||
/* Add RTP address port and codecs */
|
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
|
||||||
audio_port = 0;
|
for (i = 0; i < mgcp_msg->codecs_len; i++) {
|
||||||
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)) {
|
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
|
||||||
audio_port = mgcp_msg->audio_port;
|
MSGB_PRINTF_OR_RET(" %u", pt);
|
||||||
if (!audio_port) {
|
|
||||||
LOGPMGW(mgcp, LOGL_ERROR,
|
|
||||||
"Invalid port number, can not generate MGCP message\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", audio_port);
|
|
||||||
for (i = 0; i < mgcp_msg->ptmap_len; i++)
|
|
||||||
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
|
|
||||||
MSGB_PRINTF_OR_RET("\r\n");
|
MSGB_PRINTF_OR_RET("\r\n");
|
||||||
|
|
||||||
/* Add optional codec parameters (fmtp) */
|
/* Add optional codec parameters (fmtp) */
|
||||||
if (mgcp_msg->param_present) {
|
if (mgcp_msg->param_present) {
|
||||||
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
|
for (i = 0; i < mgcp_msg->codecs_len; i++) {
|
||||||
pt = mgcp_msg->ptmap[i].pt;
|
/* The following is only applicable for AMR */
|
||||||
switch (mgcp_msg->ptmap[i].codec) {
|
if (mgcp_msg->codecs[i] != CODEC_AMR_8000_1 && mgcp_msg->codecs[i] != CODEC_AMRWB_16000_1)
|
||||||
case CODEC_AMR_8000_1:
|
continue;
|
||||||
case CODEC_AMRWB_16000_1:
|
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
|
||||||
if (!mgcp_msg->param.amr_octet_aligned_present)
|
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
|
||||||
break;
|
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt);
|
||||||
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=%d\r\n",
|
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
|
||||||
pt, (int)mgcp_msg->param.amr_octet_aligned);
|
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=0\r\n", pt);
|
||||||
break;
|
|
||||||
case CODEC_GSM_8000_1:
|
|
||||||
case CODEC_GSMEFR_8000_1:
|
|
||||||
if (!mgcp_msg->param.fr_efr_twts001_present)
|
|
||||||
break;
|
|
||||||
MSGB_PRINTF_OR_RET("a=fmtp:%u tw-ts-001=%d\r\n",
|
|
||||||
pt, (int)mgcp_msg->param.fr_efr_twts001);
|
|
||||||
break;
|
|
||||||
case CODEC_GSMHR_8000_1:
|
|
||||||
if (!mgcp_msg->param.hr_twts002_present)
|
|
||||||
break;
|
|
||||||
MSGB_PRINTF_OR_RET("a=fmtp:%u tw-ts-002=%d\r\n",
|
|
||||||
pt, (int)mgcp_msg->param.hr_twts002);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* no parameters for the remaining codecs */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
|
for (i = 0; i < mgcp_msg->codecs_len; i++) {
|
||||||
pt = mgcp_msg->ptmap[i].pt;
|
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
|
||||||
|
|
||||||
/* Note: Only dynamic payload type from the range 96-127
|
/* Note: Only dynamic payload type from the range 96-127
|
||||||
* require to be explained further via rtpmap. All others
|
* require to be explained further via rtpmap. All others
|
||||||
* are implcitly definedby the number in m=audio */
|
* are implcitly definedby the number in m=audio */
|
||||||
if (pt >= 96 && pt <= 127) {
|
if (pt >= 96 && pt <= 127) {
|
||||||
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
|
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->codecs[i]);
|
||||||
|
|
||||||
/* Note: Use codec descriptors from enum mgcp_codecs
|
/* Note: Use codec descriptors from enum mgcp_codecs
|
||||||
* in mgcp_client only! */
|
* in mgcp_client only! */
|
||||||
@@ -1569,10 +1470,10 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
|
|||||||
MSGB_PRINTF_OR_RET("I: %s\r\n", mgcp_msg->conn_id);
|
MSGB_PRINTF_OR_RET("I: %s\r\n", mgcp_msg->conn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Using SDP makes sense when a valid IP or Port is specified,
|
/* Using SDP makes sense when a valid IP/Port combination is specified,
|
||||||
* if we do not know this information yet, we fall back to LCO */
|
* if we do not know this information yet, we fall back to LCO */
|
||||||
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
|
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
|
||||||
|| mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)
|
&& mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)
|
||||||
use_sdp = true;
|
use_sdp = true;
|
||||||
|
|
||||||
/* Add local connection options (LCO) */
|
/* Add local connection options (LCO) */
|
||||||
@@ -1670,20 +1571,3 @@ const char *mgcp_client_name(const struct mgcp_client *mgcp)
|
|||||||
else
|
else
|
||||||
return mgcp_client_endpoint_domain(mgcp);
|
return mgcp_client_endpoint_domain(mgcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Return typical cmp result, comparing a to b.
|
|
||||||
* Return 0 if a == b, -1 if a < b, 1 if a > b; comparing all members of ptmap in turn. */
|
|
||||||
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
if (a == b)
|
|
||||||
return 0;
|
|
||||||
if (!a)
|
|
||||||
return -1;
|
|
||||||
if (!b)
|
|
||||||
return 1;
|
|
||||||
rc = OSMO_CMP(a->codec, b->codec);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
return OSMO_CMP(a->pt, b->pt);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -173,30 +173,6 @@ const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
|
|||||||
return osmo_fsm_inst_name(ep->fi);
|
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)
|
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
|
/* 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),
|
mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
|
||||||
ci->notify.fi ? "" : " (not sending a notification)");
|
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)
|
if (ci->notify.fi)
|
||||||
osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
|
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
|
/*! 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));
|
osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
|
||||||
*ci = cleared_ci;
|
*ci = cleared_ci;
|
||||||
|
|
||||||
|
LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
|
||||||
|
|
||||||
if (verb_info)
|
if (verb_info)
|
||||||
ci->verb_info = *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 (ep->endpoint[0]) {
|
||||||
if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
|
if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
|
||||||
LOG_CI(ci, LOGL_ERROR,
|
LOG_CI(ci, LOGL_ERROR,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
#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/mgcp_client/mgcp_client_fsm.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/core/fsm.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,
|
.call_id = info->call_id,
|
||||||
.conn_mode = MGCP_CONN_RECV_ONLY,
|
.conn_mode = MGCP_CONN_RECV_ONLY,
|
||||||
.ptime = info->ptime,
|
.ptime = info->ptime,
|
||||||
|
.codecs_len = info->codecs_len,
|
||||||
.ptmap_len = info->ptmap_len,
|
.ptmap_len = info->ptmap_len,
|
||||||
.param_present = info->param_present
|
.param_present = info->param_present
|
||||||
};
|
};
|
||||||
osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
|
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->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
|
||||||
memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
|
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)
|
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
|
||||||
{
|
{
|
||||||
bool ip_is_set = info->addr[0] != '\0' &&
|
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT;
|
||||||
strncmp(info->addr, "::", sizeof(info->addr)) != 0 &&
|
mgcp_msg->audio_ip = info->addr;
|
||||||
strncmp(info->addr, "0.0.0.0", sizeof(info->addr)) != 0;
|
mgcp_msg->audio_port = info->port;
|
||||||
if (ip_is_set) {
|
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
|
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
|
||||||
@@ -157,7 +149,6 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
|
|||||||
mgcp_msg->conn_mode = conn_mode;
|
mgcp_msg->conn_mode = conn_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns message buffer containing MGXP MDCX on success, NULL on error. */
|
|
||||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
||||||
{
|
{
|
||||||
struct mgcp_msg mgcp_msg;
|
struct mgcp_msg mgcp_msg;
|
||||||
@@ -172,10 +163,12 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
|||||||
.audio_ip = mgcp_ctx->conn_peer_local.addr,
|
.audio_ip = mgcp_ctx->conn_peer_local.addr,
|
||||||
.audio_port = mgcp_ctx->conn_peer_local.port,
|
.audio_port = mgcp_ctx->conn_peer_local.port,
|
||||||
.ptime = mgcp_ctx->conn_peer_local.ptime,
|
.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,
|
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
|
||||||
.param_present = mgcp_ctx->conn_peer_local.param_present
|
.param_present = mgcp_ctx->conn_peer_local.param_present
|
||||||
};
|
};
|
||||||
osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
|
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.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));
|
memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
|
||||||
|
|
||||||
@@ -193,7 +186,6 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
|||||||
return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns message buffer containing MGXP DLCX on success, NULL on error. */
|
|
||||||
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
|
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
|
||||||
{
|
{
|
||||||
struct mgcp_msg mgcp_msg;
|
struct mgcp_msg mgcp_msg;
|
||||||
@@ -229,14 +221,13 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||||||
mgcp_ctx->conn_peer_local.endpoint);
|
mgcp_ctx->conn_peer_local.endpoint);
|
||||||
|
|
||||||
make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
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);
|
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||||
|
|
||||||
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
||||||
if (!msg) {
|
OSMO_ASSERT(msg);
|
||||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
|
mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
|
||||||
mgcp_ctx->mgw_trans_pending = true;
|
mgcp_ctx->mgw_trans_pending = true;
|
||||||
rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
|
rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
|
||||||
@@ -373,21 +364,13 @@ static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case EV_MDCX:
|
case EV_MDCX:
|
||||||
msg = make_mdcx_msg(mgcp_ctx);
|
msg = make_mdcx_msg(mgcp_ctx);
|
||||||
if (!msg) {
|
OSMO_ASSERT(msg);
|
||||||
/* make_mdcx_msg() should already have logged the error */
|
|
||||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
|
rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
|
||||||
new_state = ST_MDCX_RESP;
|
new_state = ST_MDCX_RESP;
|
||||||
break;
|
break;
|
||||||
case EV_DLCX:
|
case EV_DLCX:
|
||||||
msg = make_dlcx_msg(mgcp_ctx);
|
msg = make_dlcx_msg(mgcp_ctx);
|
||||||
if (!msg) {
|
OSMO_ASSERT(msg);
|
||||||
/* make_dlcx_msg() should already have logged the error */
|
|
||||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
|
rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
|
||||||
new_state = ST_DLCX_RESP;
|
new_state = ST_DLCX_RESP;
|
||||||
break;
|
break;
|
||||||
@@ -628,72 +611,6 @@ static struct osmo_fsm fsm_mgcp_client = {
|
|||||||
.log_subsys = DLMGCP,
|
.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.
|
/*! allocate FSM, and create a new connection on the MGW.
|
||||||
* \param[in] mgcp MGCP client descriptor.
|
* \param[in] mgcp MGCP client descriptor.
|
||||||
* \param[in] parent_fi Parent FSM instance.
|
* \param[in] parent_fi Parent FSM instance.
|
||||||
@@ -708,7 +625,6 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
|
|||||||
struct osmo_fsm_inst *fi;
|
struct osmo_fsm_inst *fi;
|
||||||
struct in6_addr ip_test;
|
struct in6_addr ip_test;
|
||||||
|
|
||||||
mgcp_conn_peer_compat(conn_peer);
|
|
||||||
|
|
||||||
OSMO_ASSERT(parent_fi);
|
OSMO_ASSERT(parent_fi);
|
||||||
OSMO_ASSERT(mgcp);
|
OSMO_ASSERT(mgcp);
|
||||||
@@ -748,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 mgcp_ctx *mgcp_ctx = fi->priv;
|
||||||
struct in6_addr ip_test;
|
struct in6_addr ip_test;
|
||||||
|
|
||||||
mgcp_conn_peer_compat(conn_peer);
|
|
||||||
|
|
||||||
OSMO_ASSERT(mgcp_ctx);
|
OSMO_ASSERT(mgcp_ctx);
|
||||||
OSMO_ASSERT(conn_peer);
|
OSMO_ASSERT(conn_peer);
|
||||||
|
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ DEFUN(cfg_mgw_mgw_keepalive_req_interval,
|
|||||||
|
|
||||||
/* If client already exists, apply the change immediately if possible: */
|
/* If client already exists, apply the change immediately if possible: */
|
||||||
mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
|
mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
|
||||||
if (mgcp->iofd) { /* UDP MGCP socket connected */
|
if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
|
||||||
if (mgcp->actual.keepalive.req_interval_sec > 0) {
|
if (mgcp->actual.keepalive.req_interval_sec > 0) {
|
||||||
/* Re-schedule: */
|
/* Re-schedule: */
|
||||||
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
|
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
|
||||||
@@ -375,7 +375,7 @@ DEFUN(cfg_mgw_mgw_keepalive_timeout,
|
|||||||
|
|
||||||
/* If client already exists, apply the change immediately if possible: */
|
/* If client already exists, apply the change immediately if possible: */
|
||||||
mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
|
mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
|
||||||
if (mgcp->iofd) { /* UDP MGCP socket connected */
|
if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
|
||||||
if (mgcp->actual.keepalive.timeout_sec > 0) {
|
if (mgcp->actual.keepalive.timeout_sec > 0) {
|
||||||
/* Re-schedule: */
|
/* Re-schedule: */
|
||||||
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
|
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
|
||||||
@@ -680,7 +680,7 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
|
|||||||
const struct mgcp_client *cli = pool_member->client;
|
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, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
|
||||||
vty_out(vty, "%% MGCP link: %s,%s%s",
|
vty_out(vty, "%% MGCP link: %s,%s%s",
|
||||||
cli && cli->iofd ? "connected" : "disconnected",
|
cli && cli->wq.bfd.fd != -1 ? "connected" : "disconnected",
|
||||||
cli && cli->conn_up ?
|
cli && cli->conn_up ?
|
||||||
((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
|
((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
|
||||||
"DOWN",
|
"DOWN",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ AM_CPPFLAGS = \
|
|||||||
AM_CFLAGS = \
|
AM_CFLAGS = \
|
||||||
-Wall \
|
-Wall \
|
||||||
$(LIBOSMOCORE_CFLAGS) \
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
$(LIBOSMOCODEC_CFLAGS) \
|
|
||||||
$(LIBOSMOGSM_CFLAGS) \
|
$(LIBOSMOGSM_CFLAGS) \
|
||||||
$(LIBOSMOVTY_CFLAGS) \
|
$(LIBOSMOVTY_CFLAGS) \
|
||||||
$(LIBOSMONETIF_CFLAGS) \
|
$(LIBOSMONETIF_CFLAGS) \
|
||||||
@@ -41,7 +40,6 @@ libosmo_mgcp_a_SOURCES = \
|
|||||||
mgcp_endp.c \
|
mgcp_endp.c \
|
||||||
mgcp_trunk.c \
|
mgcp_trunk.c \
|
||||||
mgcp_ratectr.c \
|
mgcp_ratectr.c \
|
||||||
mgcp_rtp_end.c \
|
|
||||||
mgcp_e1.c \
|
mgcp_e1.c \
|
||||||
mgcp_iuup.c \
|
mgcp_iuup.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
/* Helper function to dump codec information of a specified codec to a printable
|
/* Helper function to dump codec information of a specified codec to a printable
|
||||||
* string, used by dump_codec_summary() */
|
* string, used by dump_codec_summary() */
|
||||||
static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
|
static char *dump_codec(struct mgcp_rtp_codec *codec)
|
||||||
{
|
{
|
||||||
static char str[256];
|
static char str[256];
|
||||||
char *pt_str;
|
char *pt_str;
|
||||||
@@ -49,25 +49,31 @@ static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! Dump a summary of all negotiated codecs to debug log
|
/*! Dump a summary of all negotiated codecs to debug log
|
||||||
* \param[in] cset related codecset.
|
* \param[in] conn related rtp-connection. */
|
||||||
* \param[in] prefix_str Prefix string to print during logging.
|
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
|
||||||
* */
|
|
||||||
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
|
|
||||||
{
|
{
|
||||||
|
struct mgcp_rtp_end *rtp;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
struct mgcp_rtp_codec *codec;
|
||||||
|
struct mgcp_endpoint *endp;
|
||||||
|
|
||||||
if (cset->codecs_assigned == 0) {
|
rtp = &conn->end;
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
|
endp = conn->conn->endp;
|
||||||
|
|
||||||
|
if (rtp->codecs_assigned == 0) {
|
||||||
|
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
|
||||||
|
mgcp_conn_dump(conn->conn));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store parsed codec information */
|
/* Store parsed codec information */
|
||||||
for (i = 0; i < cset->codecs_assigned; i++) {
|
for (i = 0; i < rtp->codecs_assigned; i++) {
|
||||||
struct mgcp_rtp_codec *codec = &cset->codecs[i];
|
codec = &rtp->codecs[i];
|
||||||
|
|
||||||
LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
|
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
|
||||||
|
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
|
||||||
|
|
||||||
if (codec == cset->codec)
|
if (codec == rtp->codec)
|
||||||
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
|
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
|
||||||
|
|
||||||
LOGPC(DLMGCP, LOGL_DEBUG, "\n");
|
LOGPC(DLMGCP, LOGL_DEBUG, "\n");
|
||||||
@@ -75,7 +81,7 @@ void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_st
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initalize or reset codec information with default data. */
|
/* Initalize or reset codec information with default data. */
|
||||||
static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
|
static void codec_init(struct mgcp_rtp_codec *codec)
|
||||||
{
|
{
|
||||||
*codec = (struct mgcp_rtp_codec){
|
*codec = (struct mgcp_rtp_codec){
|
||||||
.payload_type = -1,
|
.payload_type = -1,
|
||||||
@@ -88,20 +94,20 @@ static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mgcp_codec_free(struct mgcp_rtp_codec *codec)
|
static void codec_free(struct mgcp_rtp_codec *codec)
|
||||||
{
|
{
|
||||||
*codec = (struct mgcp_rtp_codec){};
|
*codec = (struct mgcp_rtp_codec){};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Initalize or reset codec information with default data.
|
/*! Initalize or reset codec information with default data.
|
||||||
* \param[out] conn related rtp-connection. */
|
* \param[out] conn related rtp-connection. */
|
||||||
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
|
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < cset->codecs_assigned; i++)
|
for (i = 0; i < conn->end.codecs_assigned; i++)
|
||||||
mgcp_codec_free(&cset->codecs[i]);
|
codec_free(&conn->end.codecs[i]);
|
||||||
cset->codecs_assigned = 0;
|
conn->end.codecs_assigned = 0;
|
||||||
cset->codec = NULL;
|
conn->end.codec = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Add codec configuration depending on payload type and/or codec name. This
|
/*! Add codec configuration depending on payload type and/or codec name. This
|
||||||
@@ -112,23 +118,23 @@ void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
|
|||||||
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
|
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
|
||||||
* \param[in] param optional codec parameters (set to NULL when unused).
|
* \param[in] param optional codec parameters (set to NULL when unused).
|
||||||
* \returns 0 on success, -EINVAL on failure. */
|
* \returns 0 on success, -EINVAL on failure. */
|
||||||
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
|
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
|
||||||
{
|
{
|
||||||
int rate;
|
int rate;
|
||||||
int channels;
|
int channels;
|
||||||
struct mgcp_rtp_codec *codec;
|
struct mgcp_rtp_codec *codec;
|
||||||
unsigned int pt_offset = cset->codecs_assigned;
|
unsigned int pt_offset = conn->end.codecs_assigned;
|
||||||
|
|
||||||
/* The amount of codecs we can store is limited, make sure we do not
|
/* The amount of codecs we can store is limited, make sure we do not
|
||||||
* overrun this limit. */
|
* overrun this limit. */
|
||||||
if (cset->codecs_assigned >= MGCP_MAX_CODECS)
|
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* First unused entry */
|
/* First unused entry */
|
||||||
codec = &cset->codecs[cset->codecs_assigned];
|
codec = &conn->end.codecs[conn->end.codecs_assigned];
|
||||||
|
|
||||||
/* Initalize the codec struct with some default data to begin with */
|
/* Initalize the codec struct with some default data to begin with */
|
||||||
mgcp_codec_init(codec);
|
codec_init(codec);
|
||||||
|
|
||||||
if (payload_type != PTYPE_UNDEFINED) {
|
if (payload_type != PTYPE_UNDEFINED) {
|
||||||
/* Make sure we do not get any reserved or undefined type numbers */
|
/* Make sure we do not get any reserved or undefined type numbers */
|
||||||
@@ -262,11 +268,11 @@ int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, co
|
|||||||
} else
|
} else
|
||||||
codec->param_present = false;
|
codec->param_present = false;
|
||||||
|
|
||||||
cset->codecs_assigned++;
|
conn->end.codecs_assigned++;
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
/* Make sure we leave a clean codec entry on error. */
|
/* Make sure we leave a clean codec entry on error. */
|
||||||
mgcp_codec_free(codec);
|
codec_free(codec);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +296,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compare two codecs, all parameters must match up */
|
/* Compare two codecs, all parameters must match up */
|
||||||
static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
|
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
|
/* 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
|
* exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
|
||||||
@@ -319,7 +325,7 @@ static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
|
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
|
||||||
static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
|
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
|
/* 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.
|
* translate between different payload formats as long as the encoded voice data itself does not change.
|
||||||
@@ -348,18 +354,21 @@ iufp:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
|
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
|
||||||
{
|
{
|
||||||
|
struct mgcp_rtp_end *rtp_end;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int codecs_assigned;
|
unsigned int codecs_assigned;
|
||||||
|
|
||||||
|
rtp_end = &conn->end;
|
||||||
|
|
||||||
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
|
/* 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. */
|
* the first run we will look for an exact match. */
|
||||||
codecs_assigned = cset->codecs_assigned;
|
codecs_assigned = rtp_end->codecs_assigned;
|
||||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||||
for (i = 0; i < codecs_assigned; i++) {
|
for (i = 0; i < codecs_assigned; i++) {
|
||||||
if (codecs_same(codec, &cset->codecs[i])) {
|
if (codecs_same(codec, &rtp_end->codecs[i])) {
|
||||||
return &cset->codecs[i];
|
return &rtp_end->codecs[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,26 +377,28 @@ struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For a given codec, find a convertible codec in the given connection. */
|
/* For a given codec, find a convertible codec in the given connection. */
|
||||||
static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
|
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 i;
|
||||||
unsigned int codecs_assigned;
|
unsigned int codecs_assigned;
|
||||||
struct mgcp_rtp_codec *codec_convertible = NULL;
|
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
|
/* 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. */
|
* the first run we will look for an exact match. */
|
||||||
codec_convertible = mgcp_codecset_find_same(cset, codec);
|
codec_convertible = mgcp_codec_find_same(conn, codec);
|
||||||
if (codec_convertible)
|
if (codec_convertible)
|
||||||
return 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
|
/* 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) */
|
* payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
|
||||||
codecs_assigned = cset->codecs_assigned;
|
codecs_assigned = rtp_end->codecs_assigned;
|
||||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||||
for (i = 0; i < codecs_assigned; i++) {
|
for (i = 0; i < codecs_assigned; i++) {
|
||||||
if (codecs_convertible(codec, &cset->codecs[i])) {
|
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
|
||||||
codec_convertible = &cset->codecs[i];
|
codec_convertible = &rtp_end->codecs[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,20 +408,20 @@ static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset
|
|||||||
|
|
||||||
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
|
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
|
||||||
* a tentative decision is made.
|
* a tentative decision is made.
|
||||||
* \param[in] cset_src related codec set.
|
* \param[inout] conn_src related rtp-connection.
|
||||||
* \param[inout] cset_dst related destination codec set (NULL if not present).
|
* \param[inout] conn_dst related destination rtp-connection (NULL if not present).
|
||||||
* \returns 0 on success, -EINVAL on failure. */
|
* \returns 0 on success, -EINVAL on failure. */
|
||||||
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
|
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* In case no destination connection is available (yet), or in case the destination connection exists but has
|
/* 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:
|
* no codecs assigned, we are forced to make a simple tentative decision:
|
||||||
* We just use the first codec of the source connection (conn_src) */
|
* We just use the first codec of the source connection (conn_src) */
|
||||||
OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
|
OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
|
||||||
if (!cset_dst || cset_dst->codecs_assigned == 0) {
|
if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
|
||||||
if (cset_src->codecs_assigned >= 1) {
|
if (conn_src->end.codecs_assigned >= 1) {
|
||||||
cset_src->codec = &cset_src->codecs[0];
|
conn_src->end.codec = &conn_src->end.codecs[0];
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -419,42 +430,33 @@ int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_cod
|
|||||||
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
|
/* 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
|
* of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
|
||||||
* required. */
|
* required. */
|
||||||
for (i = 0; i < cset_src->codecs_assigned; i++) {
|
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
|
||||||
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
|
struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, &conn_src->end.codecs[i]);
|
||||||
struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
|
if (codec_conn_dst) {
|
||||||
if (codec_cset_dst) {
|
|
||||||
/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
|
/* 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. */
|
* sides. We now set this codec on both connections. */
|
||||||
cset_dst->codec = codec_cset_dst;
|
conn_dst->end.codec = codec_conn_dst;
|
||||||
cset_src->codec = codec_cset_src;
|
conn_src->end.codec = mgcp_codec_find_same(conn_src, codec_conn_dst);
|
||||||
|
OSMO_ASSERT(conn_src->end.codec);
|
||||||
return 0;
|
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
|
/* 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. */
|
* to convert. */
|
||||||
for (i = 0; i < cset_src->codecs_assigned; i++) {
|
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
|
||||||
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
|
struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, &conn_src->end.codecs[i]);
|
||||||
struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
|
if (codec_conn_dst) {
|
||||||
if (codec_cset_dst) {
|
/* We found the a codec that we are able to convert on both sides. We now set this codec on both
|
||||||
/* We found the a codec that we can convert to. Set each side to its codec. */
|
* connections. */
|
||||||
cset_dst->codec = codec_cset_dst;
|
conn_dst->end.codec = codec_conn_dst;
|
||||||
cset_src->codec = codec_cset_src;
|
conn_src->end.codec = codec_find_convertible(conn_src, codec_conn_dst);
|
||||||
|
OSMO_ASSERT(conn_src->end.codec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cset_dst->codecs_assigned)
|
return -EINVAL;
|
||||||
cset_dst->codec = &cset_dst->codecs[0];
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (cset_src->codecs_assigned)
|
|
||||||
cset_src->codec = &cset_src->codecs[0];
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
|
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
|
||||||
@@ -477,36 +479,38 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
|
|||||||
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
|
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
|
||||||
* with incrementing match_nr.
|
* 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_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
|
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)
|
const char *subtype_name, unsigned int match_nr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < cset->codecs_assigned; i++) {
|
for (i = 0; i < conn->end.codecs_assigned; i++) {
|
||||||
if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
|
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
|
||||||
if (match_nr) {
|
if (match_nr) {
|
||||||
match_nr--;
|
match_nr--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return &cset->codecs[i];
|
return &conn->end.codecs[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Lookup a codec that is assigned to a connection by its payload type number.
|
/*! Lookup a codec that is assigned to a connection by its payload type number.
|
||||||
* \param[in] cset related codec set.
|
* \param[in] conn related rtp-connection.
|
||||||
* \param[in] payload_type number of the codec to look up.
|
* \param[in] payload_type number of the codec to look up.
|
||||||
* \returns pointer to codec struct on success, NULL on failure. */
|
* \returns pointer to codec struct on success, NULL on failure. */
|
||||||
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
|
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;
|
struct mgcp_rtp_codec *codec = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
|
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||||
|
|
||||||
for (i = 0; i < cset->codecs_assigned; i++) {
|
for (i = 0; i < codecs_assigned; i++) {
|
||||||
if (payload_type == cset->codecs[i].payload_type) {
|
if (payload_type == rtp_end->codecs[i].payload_type) {
|
||||||
codec = &cset->codecs[i];
|
codec = &rtp_end->codecs[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
|
|||||||
|
|
||||||
/* ensure that the generated conn_id is unique
|
/* ensure that the generated conn_id is unique
|
||||||
* for this endpoint */
|
* for this endpoint */
|
||||||
if (!mgcp_endp_get_conn_rtp(endp, id_hex)) {
|
if (!mgcp_conn_get_rtp(endp, id_hex)) {
|
||||||
osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
|
osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -88,6 +88,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
|
|||||||
/* Initialize rtp connection struct with default values */
|
/* Initialize rtp connection struct with default values */
|
||||||
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
|
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
|
||||||
{
|
{
|
||||||
|
struct mgcp_rtp_end *end = &conn_rtp->end;
|
||||||
/* FIXME: Each new rate counter group requires an unique index. At the
|
/* FIXME: Each new rate counter group requires an unique index. At the
|
||||||
* moment we generate this index using this counter, but perhaps there
|
* moment we generate this index using this counter, but perhaps there
|
||||||
* is a more concious way to assign the indexes. */
|
* is a more concious way to assign the indexes. */
|
||||||
@@ -105,6 +106,19 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
|
|||||||
/* backpointer to the generic part of the connection */
|
/* backpointer to the generic part of the connection */
|
||||||
conn->u.rtp.conn = conn;
|
conn->u.rtp.conn = conn;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
|
||||||
|
end->output_enabled = false;
|
||||||
|
end->maximum_packet_time = -1;
|
||||||
|
|
||||||
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
|
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
|
||||||
if (!conn_rtp->ctrg)
|
if (!conn_rtp->ctrg)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -112,7 +126,9 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
|
|||||||
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
|
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
|
||||||
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
|
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
|
||||||
|
|
||||||
mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
|
/* Make sure codec table is reset */
|
||||||
|
mgcp_codec_reset_all(conn_rtp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,15 +139,16 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
|
|||||||
conn_osmux_disable(conn_rtp);
|
conn_osmux_disable(conn_rtp);
|
||||||
if (mgcp_conn_rtp_is_iuup(conn_rtp))
|
if (mgcp_conn_rtp_is_iuup(conn_rtp))
|
||||||
mgcp_conn_iuup_cleanup(conn_rtp);
|
mgcp_conn_iuup_cleanup(conn_rtp);
|
||||||
mgcp_rtp_end_cleanup(&conn_rtp->end);
|
mgcp_free_rtp_port(&conn_rtp->end);
|
||||||
rate_ctr_group_free(conn_rtp->ctrg);
|
rate_ctr_group_free(conn_rtp->ctrg);
|
||||||
|
mgcp_codec_reset_all(conn_rtp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mgcp_conn_watchdog_cb(void *data)
|
void mgcp_conn_watchdog_cb(void *data)
|
||||||
{
|
{
|
||||||
struct mgcp_conn *conn = data;
|
struct mgcp_conn *conn = data;
|
||||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
|
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
|
||||||
mgcp_conn_free(conn);
|
mgcp_conn_free(conn->endp, conn->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
|
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
|
||||||
@@ -156,8 +173,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
|||||||
struct mgcp_conn *conn;
|
struct mgcp_conn *conn;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Do not allow more than the maximum number of connections */
|
/* Do not allow more then the maximum number of connections */
|
||||||
if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns)
|
if (endp->type->max_conns && llist_count(&endp->conns) >= endp->type->max_conns)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Create new connection and add it to the list */
|
/* Create new connection and add it to the list */
|
||||||
@@ -197,6 +214,58 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! find a connection by its ID.
|
||||||
|
* \param[in] endp associated endpoint
|
||||||
|
* \param[in] id identification number of the connection
|
||||||
|
* \returns pointer to allocated connection, NULL if not found */
|
||||||
|
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
|
||||||
|
{
|
||||||
|
struct mgcp_conn *conn;
|
||||||
|
const char *id_upper;
|
||||||
|
const char *conn_id;
|
||||||
|
|
||||||
|
if (!id || !*id)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Ignore leading zeros in needle */
|
||||||
|
while (*id == '0')
|
||||||
|
id++;
|
||||||
|
|
||||||
|
/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
|
||||||
|
* Connections" defines the id as a hex string, so clients may return lower case hex even though
|
||||||
|
* we sent upper case hex in the CRCX response. */
|
||||||
|
id_upper = osmo_str_toupper(id);
|
||||||
|
|
||||||
|
llist_for_each_entry(conn, &endp->conns, entry) {
|
||||||
|
/* Ignore leading zeros in haystack */
|
||||||
|
for (conn_id=conn->id; *conn_id == '0'; conn_id++);
|
||||||
|
|
||||||
|
if (strcmp(conn_id, id_upper) == 0)
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! find an RTP connection by its ID.
|
||||||
|
* \param[in] endp associated endpoint
|
||||||
|
* \param[in] id identification number of the connection
|
||||||
|
* \returns pointer to allocated connection, NULL if not found */
|
||||||
|
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
|
||||||
|
const char *id)
|
||||||
|
{
|
||||||
|
struct mgcp_conn *conn;
|
||||||
|
|
||||||
|
conn = mgcp_conn_get(endp, id);
|
||||||
|
if (!conn)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (conn->type == MGCP_CONN_TYPE_RTP)
|
||||||
|
return &conn->u.rtp;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
|
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
|
||||||
{
|
{
|
||||||
struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
|
struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
|
||||||
@@ -219,21 +288,21 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
|
|||||||
rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
|
rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! free a connection
|
/*! free a connection by its ID.
|
||||||
* \param[in] conn the conn to free. May be NULL.
|
* \param[in] endp associated endpoint
|
||||||
*/
|
* \param[in] id identification number of the connection */
|
||||||
void mgcp_conn_free(struct mgcp_conn *conn)
|
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
|
||||||
{
|
{
|
||||||
struct mgcp_conn_rtp *conn_rtp;
|
struct mgcp_conn *conn;
|
||||||
|
|
||||||
|
conn = mgcp_conn_get(endp, id);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (conn->type) {
|
switch (conn->type) {
|
||||||
case MGCP_CONN_TYPE_RTP:
|
case MGCP_CONN_TYPE_RTP:
|
||||||
conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
aggregate_rtp_conn_stats(endp, &conn->u.rtp);
|
||||||
aggregate_rtp_conn_stats(conn->endp, conn_rtp);
|
mgcp_rtp_conn_cleanup(&conn->u.rtp);
|
||||||
mgcp_rtp_conn_cleanup(conn_rtp);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* NOTE: This should never be called with an
|
/* NOTE: This should never be called with an
|
||||||
@@ -243,40 +312,43 @@ void mgcp_conn_free(struct mgcp_conn *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
osmo_timer_del(&conn->watchdog);
|
osmo_timer_del(&conn->watchdog);
|
||||||
mgcp_endp_remove_conn(conn->endp, conn);
|
mgcp_endp_remove_conn(endp, conn);
|
||||||
/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
|
/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
|
||||||
talloc_free(conn);
|
talloc_free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse connection mode.
|
/*! free oldest connection in the list.
|
||||||
* \param[in] conn Connection whose mode is being set
|
* \param[in] endp associated endpoint */
|
||||||
* \param[in] mode Mode to set
|
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
|
||||||
* \returns 0 on success, -1 on error */
|
|
||||||
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode)
|
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(conn);
|
struct mgcp_conn *conn;
|
||||||
if (mode == MGCP_CONN_NONE) {
|
|
||||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
|
|
||||||
"missing connection mode\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
conn->mode = mode;
|
|
||||||
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
|
|
||||||
mgcp_cmode_name(mode), conn->mode);
|
|
||||||
|
|
||||||
/* Special handling for RTP connections */
|
if (llist_empty(&endp->conns))
|
||||||
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
return;
|
||||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
|
||||||
conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
|
|
||||||
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
|
|
||||||
conn_rtp->end.output_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The VTY might change the connection mode at any time, so we have
|
conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
||||||
* to hold a copy of the original connection mode */
|
if (!conn)
|
||||||
conn->mode_orig = conn->mode;
|
return;
|
||||||
|
|
||||||
return 0;
|
mgcp_conn_free(endp, conn->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! free all connections at once.
|
||||||
|
* \param[in] endp associated endpoint */
|
||||||
|
#if defined(__has_attribute)
|
||||||
|
#if __has_attribute(no_sanitize)
|
||||||
|
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
|
||||||
|
{
|
||||||
|
struct mgcp_conn *conn;
|
||||||
|
|
||||||
|
/* Drop all items in the list, might be consecutive! */
|
||||||
|
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
|
||||||
|
mgcp_conn_free(endp, conn->id);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! dump basic connection information to human readable string.
|
/*! dump basic connection information to human readable string.
|
||||||
@@ -286,39 +358,53 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
|
|||||||
{
|
{
|
||||||
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
|
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
|
||||||
char ipbuf[INET6_ADDRSTRLEN];
|
char ipbuf[INET6_ADDRSTRLEN];
|
||||||
struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
|
|
||||||
struct mgcp_conn_rtp *conn_rtp;
|
|
||||||
|
|
||||||
if (!conn)
|
if (!conn) {
|
||||||
return "NULL";
|
snprintf(str, sizeof(str), "(null connection)");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
switch (conn->type) {
|
switch (conn->type) {
|
||||||
case MGCP_CONN_TYPE_RTP:
|
case MGCP_CONN_TYPE_RTP:
|
||||||
conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
switch (conn->u.rtp.type) {
|
||||||
OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
|
case MGCP_RTP_DEFAULT:
|
||||||
conn->name,
|
/* Dump RTP connection */
|
||||||
mgcp_conn_rtp_type_name(conn->type),
|
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
|
||||||
conn->id,
|
"rtp:%u rtcp:%u)",
|
||||||
osmo_sockaddr_ntop(&conn_rtp->end.addr.u.sa, ipbuf) ? : "NULL",
|
conn->name, conn->id,
|
||||||
osmo_sockaddr_port(&conn_rtp->end.addr.u.sa),
|
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
|
||||||
conn_rtp->end.local_addr ? : "NULL",
|
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
|
||||||
conn_rtp->end.local_port);
|
ntohs(conn->u.rtp.end.rtcp_port));
|
||||||
|
break;
|
||||||
switch (conn_rtp->type) {
|
|
||||||
case MGCP_RTP_OSMUX:
|
case MGCP_RTP_OSMUX:
|
||||||
OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_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;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSMO_STRBUF_PRINTF(sb, ")");
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Should not happen, we should be able to dump
|
/* Should not happen, we should be able to dump
|
||||||
* every possible connection type. */
|
* every possible connection type. */
|
||||||
return "(unknown connection type)";
|
snprintf(str, sizeof(str), "(unknown connection type)");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
@@ -346,9 +432,12 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct value_string mgcp_conn_rtp_type_names[] = {
|
/*! get oldest connection in the list.
|
||||||
{ MGCP_RTP_DEFAULT, "rtp" },
|
* \param[in] endp associated endpoint */
|
||||||
{ MGCP_RTP_OSMUX, "osmux" },
|
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
|
||||||
{ MGCP_RTP_IUUP, "iuup" },
|
{
|
||||||
{}
|
if (llist_empty(&endp->conns))
|
||||||
};
|
return NULL;
|
||||||
|
|
||||||
|
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
#include <osmocom/mgcp/debug.h>
|
#include <osmocom/mgcp/debug.h>
|
||||||
#include <osmocom/mgcp/mgcp_e1.h>
|
#include <osmocom/mgcp/mgcp_e1.h>
|
||||||
#include <osmocom/codec/codec.h>
|
#include <osmocom/codec/codec.h>
|
||||||
#include <osmocom/gsm/rtp_extensions.h>
|
|
||||||
|
|
||||||
#define DEBUG_BITS_MAX 80
|
#define DEBUG_BITS_MAX 80
|
||||||
#define DEBUG_BYTES_MAX 40
|
#define DEBUG_BYTES_MAX 40
|
||||||
@@ -57,6 +56,135 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
|
|||||||
.sign_link = NULL,
|
.sign_link = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* EFR idle frame */
|
||||||
|
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 0, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FR idle frame */
|
||||||
|
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
|
||||||
|
static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 0, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
|
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
|
||||||
* run empty. In order to make sure that the TRAU frame transmission continues
|
* run empty. In order to make sure that the TRAU frame transmission continues
|
||||||
* we generate idle TRAU frames here. */
|
* we generate idle TRAU frames here. */
|
||||||
@@ -65,59 +193,33 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
|
|||||||
struct mgcp_endpoint *endp = user_data;
|
struct mgcp_endpoint *endp = user_data;
|
||||||
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
||||||
struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
|
struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
|
||||||
const uint8_t *dummy_fill_pl;
|
uint8_t *ptr;
|
||||||
unsigned dummy_fill_pl_len;
|
const uint8_t *ptr_ft;
|
||||||
struct osmo_trau_frame tf;
|
enum osmo_trau_frame_type ft;
|
||||||
int rc;
|
|
||||||
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
|
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
|
||||||
|
|
||||||
/* choose dummy fill frame payload based on current codec */
|
/* Choose an appropiate idle frame type */
|
||||||
switch (endp->e1.trau_rtp_st->type) {
|
ft = endp->e1.trau_rtp_st->type;
|
||||||
|
switch (ft) {
|
||||||
case OSMO_TRAU16_FT_FR:
|
case OSMO_TRAU16_FT_FR:
|
||||||
dummy_fill_pl = osmo_gsm611_silence_frame;
|
ptr_ft = idle_tf_fr;
|
||||||
dummy_fill_pl_len = GSM_FR_BYTES;
|
|
||||||
break;
|
break;
|
||||||
case OSMO_TRAU16_FT_EFR:
|
case OSMO_TRAU16_FT_EFR:
|
||||||
dummy_fill_pl = osmo_gsm660_homing_frame;
|
ptr_ft = idle_tf_efr;
|
||||||
dummy_fill_pl_len = GSM_EFR_BYTES;
|
|
||||||
break;
|
|
||||||
case OSMO_TRAU16_FT_HR:
|
|
||||||
case OSMO_TRAU8_SPEECH:
|
|
||||||
dummy_fill_pl = osmo_gsm620_silence_frame;
|
|
||||||
dummy_fill_pl_len = GSM_HR_BYTES;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-I.460-IDLE-TX: unsupported frame type\n");
|
/* FIXME: What about 8k subslots and AMR frames? */
|
||||||
goto skip;
|
ptr_ft = idle_tf_spch;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* turn it into a TRAU-DL frame */
|
/* Put the replacement into a message buffer and enqueue it into the
|
||||||
memset(&tf, 0, sizeof(tf));
|
* I.460 multiplexer */
|
||||||
tf.dir = OSMO_TRAU_DIR_DL;
|
ptr = msgb_put(msg, E1_TRAU_BITS);
|
||||||
rc = osmo_rtp2trau(&tf, dummy_fill_pl, dummy_fill_pl_len, endp->e1.trau_rtp_st);
|
memcpy(ptr, ptr_ft, E1_TRAU_BITS);
|
||||||
if (rc < 0) {
|
|
||||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
|
||||||
"E1-I.460-IDLE-TX: error converting dummy fill frame!\n");
|
|
||||||
goto skip;
|
|
||||||
}
|
|
||||||
rc = osmo_trau_frame_encode(msgb_data(msg), msg->data_len, &tf);
|
|
||||||
if (rc < 0) {
|
|
||||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
|
||||||
"E1-I.460-IDLE-TX: error encoding dummy fill frame!\n");
|
|
||||||
goto skip;
|
|
||||||
}
|
|
||||||
msgb_put(msg, rc);
|
|
||||||
|
|
||||||
/* enqueue it into the I.460 multiplexer */
|
|
||||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg),
|
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg),
|
||||||
osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg)));
|
osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg)));
|
||||||
osmo_i460_mux_enqueue(endp->e1.schan, msg);
|
osmo_i460_mux_enqueue(endp->e1.schan, msg);
|
||||||
return;
|
|
||||||
|
|
||||||
skip:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
|
|
||||||
msgb_free(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
|
/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
|
||||||
@@ -178,7 +280,6 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
|
|||||||
/* Convert decoded trau frame to RTP frame */
|
/* Convert decoded trau frame to RTP frame */
|
||||||
struct osmo_trau2rtp_state t2rs = {
|
struct osmo_trau2rtp_state t2rs = {
|
||||||
.type = fr.type,
|
.type = fr.type,
|
||||||
.rtp_extensions = endp->e1.rtp_extensions,
|
|
||||||
};
|
};
|
||||||
rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);
|
rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
@@ -200,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);
|
mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
|
||||||
|
|
||||||
|
msgb_free(msg);
|
||||||
return;
|
return;
|
||||||
skip:
|
skip:
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
|
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
|
||||||
@@ -223,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)));
|
msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
|
||||||
#endif
|
#endif
|
||||||
/* Hand data over to the E1 stack */
|
/* Hand data over to the E1 stack */
|
||||||
e1inp_ts_send_raw(ts, msg);
|
msgb_enqueue(&ts->raw.tx_queue, msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,21 +466,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
|
|||||||
{
|
{
|
||||||
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
||||||
return OSMO_TRAU16_FT_FR;
|
return OSMO_TRAU16_FT_FR;
|
||||||
|
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
||||||
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
|
||||||
return OSMO_TRAU16_FT_EFR;
|
return OSMO_TRAU16_FT_EFR;
|
||||||
|
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
|
||||||
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
|
return OSMO_TRAU16_FT_HR;
|
||||||
if (i460_rate == OSMO_I460_RATE_16k)
|
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
|
||||||
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) {
|
|
||||||
if (i460_rate == OSMO_I460_RATE_8k) {
|
if (i460_rate == OSMO_I460_RATE_8k) {
|
||||||
switch (amr_ft) {
|
switch (amr_ft) {
|
||||||
case AMR_4_75:
|
case AMR_4_75:
|
||||||
@@ -396,11 +488,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return OSMO_TRAU16_FT_AMR;
|
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 */
|
/* Determine a suitable TRAU frame type for a given codec */
|
||||||
@@ -409,21 +501,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
|
|||||||
{
|
{
|
||||||
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
||||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||||
|
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
||||||
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
|
||||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||||
|
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
|
||||||
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
|
return OSMO_TRAU_SYNCP_8_HR;
|
||||||
if (i460_rate == OSMO_I460_RATE_16k)
|
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
|
||||||
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) {
|
|
||||||
if (i460_rate == OSMO_I460_RATE_8k) {
|
if (i460_rate == OSMO_I460_RATE_8k) {
|
||||||
switch (amr_ft) {
|
switch (amr_ft) {
|
||||||
case AMR_4_75:
|
case AMR_4_75:
|
||||||
@@ -441,11 +523,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
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 */
|
/* Find out if a given TRAU frame type is AMR */
|
||||||
@@ -546,20 +628,18 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
|
|||||||
|
|
||||||
/*! Update E1 related parameters (codec and sync pattern).
|
/*! Update E1 related parameters (codec and sync pattern).
|
||||||
* \param[in] endp endpoint to update. */
|
* \param[in] endp endpoint to update. */
|
||||||
int mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
||||||
{
|
{
|
||||||
struct mgcp_conn *conn;
|
struct mgcp_conn *conn;
|
||||||
struct mgcp_conn_rtp *conn_rtp;
|
|
||||||
struct mgcp_rtp_codec *codec;
|
struct mgcp_rtp_codec *codec;
|
||||||
enum osmo_tray_sync_pat_id sync_pat_id;
|
enum osmo_tray_sync_pat_id sync_pat_id;
|
||||||
|
|
||||||
/* In order to determine the codec, find the oldest connection on
|
/* In order to determine the codec, find the oldest connection on
|
||||||
* the endpoint and use its codec information. Normally on an E1
|
* the endpoint and use its codec information. Normally on an E1
|
||||||
* endpoint no more than one connection should exist. */
|
* endpoint no more than one connection should exist. */
|
||||||
conn = mgcp_endp_get_conn_oldest(endp);
|
conn = mgcp_conn_get_oldest(endp);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
codec = conn->u.rtp.end.codec;
|
||||||
codec = conn_rtp->end.cset.codec;
|
|
||||||
OSMO_ASSERT(codec);
|
OSMO_ASSERT(codec);
|
||||||
|
|
||||||
/* Update codec information */
|
/* Update codec information */
|
||||||
@@ -567,17 +647,9 @@ int mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
|||||||
determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
||||||
endp->e1.last_codec = codec;
|
endp->e1.last_codec = codec;
|
||||||
|
|
||||||
/* possible RTP extensions, codec-associated */
|
|
||||||
endp->e1.rtp_extensions = 0;
|
|
||||||
if (codec->param_present && codec->param.fr_efr_twts001)
|
|
||||||
endp->e1.rtp_extensions |= OSMO_RTP_EXT_TWTS001;
|
|
||||||
if (codec->param_present && codec->param.hr_twts002)
|
|
||||||
endp->e1.rtp_extensions |= OSMO_RTP_EXT_TWTS002;
|
|
||||||
|
|
||||||
/* Update sync pattern */
|
/* Update sync pattern */
|
||||||
sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
||||||
osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id);
|
osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Remove E1 resources from endpoint
|
/*! Remove E1 resources from endpoint
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <osmocom/mgcp/mgcp.h>
|
#include <osmocom/mgcp/mgcp.h>
|
||||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||||
#include <osmocom/mgcp/mgcp_conn.h>
|
#include <osmocom/mgcp/mgcp_conn.h>
|
||||||
#include <osmocom/mgcp/mgcp_iuup.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_endp.h>
|
#include <osmocom/mgcp/mgcp_endp.h>
|
||||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||||
|
|
||||||
@@ -59,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate E1 endpoint name from given numeric parameters */
|
/* Generate E1 endpoint name from given numeric parameters */
|
||||||
static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr,
|
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
|
||||||
uint8_t ts_nr, uint8_t ss_nr)
|
uint8_t ts_nr, uint8_t ss_nr)
|
||||||
{
|
{
|
||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
@@ -447,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname)
|
|||||||
/* Check if the selected E1 endpoint is avalable, which means that none of
|
/* Check if the selected E1 endpoint is avalable, which means that none of
|
||||||
* the overlapping endpoints are currently serving a call. (if the system
|
* the overlapping endpoints are currently serving a call. (if the system
|
||||||
* is properly configured such a situation should never ocurr!) */
|
* is properly configured such a situation should never ocurr!) */
|
||||||
static bool endp_avail_e1(const struct mgcp_endpoint *endp)
|
static bool endp_avail_e1(struct mgcp_endpoint *endp)
|
||||||
{
|
{
|
||||||
/* The following map shows the overlapping of the subslots and their
|
/* The following map shows the overlapping of the subslots and their
|
||||||
* respective rates. The numbers on the right running from top to bottom
|
* respective rates. The numbers on the right running from top to bottom
|
||||||
@@ -553,7 +552,7 @@ static bool endp_avail_e1(const struct mgcp_endpoint *endp)
|
|||||||
/*! check if an endpoint is available for any kind of operation.
|
/*! check if an endpoint is available for any kind of operation.
|
||||||
* \param[in] endp endpoint to check.
|
* \param[in] endp endpoint to check.
|
||||||
* \returns true if endpoint is avalable, false it is blocked for any reason. */
|
* \returns true if endpoint is avalable, false it is blocked for any reason. */
|
||||||
bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
|
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
|
||||||
{
|
{
|
||||||
switch (endp->trunk->trunk_type) {
|
switch (endp->trunk->trunk_type) {
|
||||||
case MGCP_TRUNK_VIRTUAL:
|
case MGCP_TRUNK_VIRTUAL:
|
||||||
@@ -570,24 +569,6 @@ bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get number of conns in an endpoint.
|
|
||||||
* \param[in] endp endpoint to check.
|
|
||||||
* \returns Number of connections present in the endpoint. */
|
|
||||||
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp)
|
|
||||||
{
|
|
||||||
return llist_count(&endp->conns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! check if an endpoint can in current state allocate new conns.
|
|
||||||
* \param[in] endp endpoint to check.
|
|
||||||
* \returns true if more connections can be allowed on endpoint, false if it is already busy. */
|
|
||||||
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp)
|
|
||||||
{
|
|
||||||
if (endp->type->max_conns == 0)
|
|
||||||
return false;
|
|
||||||
return mgcp_endp_num_conns(endp) >= endp->type->max_conns;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! claim endpoint, sets callid and activates endpoint, should be called at the
|
/*! claim endpoint, sets callid and activates endpoint, should be called at the
|
||||||
* beginning of the CRCX procedure when it is clear that a new call should be
|
* beginning of the CRCX procedure when it is clear that a new call should be
|
||||||
* created.
|
* created.
|
||||||
@@ -641,85 +622,20 @@ int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
|
|||||||
|
|
||||||
/*! update endpoint, updates internal endpoint specific data, should be
|
/*! update endpoint, updates internal endpoint specific data, should be
|
||||||
* after when MDCX or CRCX has been executed successuflly.
|
* after when MDCX or CRCX has been executed successuflly.
|
||||||
* \param[in] endp endpoint to update.
|
* \param[in] endp endpoint to update. */
|
||||||
* \returns zero on success, mgcp negative error on failure. */
|
void mgcp_endp_update(struct mgcp_endpoint *endp)
|
||||||
static int mgcp_endp_update_virtual(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb)
|
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(conn);
|
|
||||||
OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
|
|
||||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
|
||||||
|
|
||||||
switch (conn_rtp->type) {
|
|
||||||
case MGCP_RTP_DEFAULT:
|
|
||||||
break;
|
|
||||||
case MGCP_RTP_OSMUX:
|
|
||||||
if (conn_osmux_event_rx_crcx_mdcx(conn_rtp) < 0) {
|
|
||||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
|
|
||||||
return -500;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MGCP_RTP_IUUP:
|
|
||||||
return mgcp_conn_iuup_event_rx_crcx_mdcx(conn_rtp);
|
|
||||||
default:
|
|
||||||
return -523;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! update endpoint, updates internal endpoint specific data, should be
|
|
||||||
* after when MDCX or CRCX has been executed successuflly.
|
|
||||||
* \param[in] endp endpoint to update.
|
|
||||||
* \returns zero on success, mgcp negative error on failure. */
|
|
||||||
int mgcp_endp_update(struct mgcp_endpoint *endp, struct mgcp_conn *conn, enum mgcp_verb verb)
|
|
||||||
{
|
|
||||||
OSMO_ASSERT(conn);
|
|
||||||
struct mgcp_trunk *trunk = endp->trunk;
|
|
||||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
|
||||||
char new_local_addr[INET6_ADDRSTRLEN];
|
|
||||||
|
|
||||||
/* CRCX: Find a local address for conn based on policy and initial SDP remote
|
|
||||||
* information, then find a free port for it.
|
|
||||||
* MDCX: msg may have provided a new remote address, which means we may need
|
|
||||||
* to update our announced IP addr and re-bind our local end. This can
|
|
||||||
* happen for instance if MGW initially provided an IPv4 during CRCX
|
|
||||||
* ACK, and now MDCX tells us the remote has an IPv6 address.
|
|
||||||
*/
|
|
||||||
if (mgcp_get_local_addr(new_local_addr, conn_rtp) < 0)
|
|
||||||
goto fail_bind_port_ret;
|
|
||||||
|
|
||||||
if (strcmp(new_local_addr, conn_rtp->end.local_addr)) {
|
|
||||||
osmo_strlcpy(conn_rtp->end.local_addr, new_local_addr, sizeof(conn_rtp->end.local_addr));
|
|
||||||
mgcp_rtp_end_free_port(&conn_rtp->end);
|
|
||||||
if (mgcp_trunk_allocate_conn_rtp_ports(trunk, conn_rtp) != 0)
|
|
||||||
goto fail_bind_port_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate resources */
|
/* Allocate resources */
|
||||||
switch (endp->trunk->trunk_type) {
|
switch (endp->trunk->trunk_type) {
|
||||||
case MGCP_TRUNK_VIRTUAL:
|
case MGCP_TRUNK_VIRTUAL:
|
||||||
return mgcp_endp_update_virtual(endp, conn, verb);
|
/* No updating initaliziation required for virtual endpoints. */
|
||||||
|
break;
|
||||||
case MGCP_TRUNK_E1:
|
case MGCP_TRUNK_E1:
|
||||||
return mgcp_e1_endp_update(endp);
|
mgcp_e1_endp_update(endp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
OSMO_ASSERT(false);
|
OSMO_ASSERT(false);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail_bind_port_ret:
|
|
||||||
switch (verb) {
|
|
||||||
case MGCP_VERB_CRCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(trunk->ratectr.mgcp_crcx_ctr_group,
|
|
||||||
MGCP_CRCX_FAIL_BIND_PORT));
|
|
||||||
break;
|
|
||||||
case MGCP_VERB_MDCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(trunk->ratectr.mgcp_mdcx_ctr_group,
|
|
||||||
MGCP_MDCX_FAIL_BIND_PORT));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
||||||
@@ -739,113 +655,6 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
|||||||
mgcp_endp_release(endp);
|
mgcp_endp_release(endp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! free oldest connection in the list.
|
|
||||||
* \param[in] endp associated endpoint */
|
|
||||||
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp)
|
|
||||||
{
|
|
||||||
struct mgcp_conn *conn;
|
|
||||||
|
|
||||||
if (llist_empty(&endp->conns))
|
|
||||||
return;
|
|
||||||
|
|
||||||
conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
|
||||||
mgcp_conn_free(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! free all connections at once.
|
|
||||||
* \param[in] endp associated endpoint */
|
|
||||||
#if defined(__has_attribute)
|
|
||||||
#if __has_attribute(no_sanitize)
|
|
||||||
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp)
|
|
||||||
{
|
|
||||||
struct mgcp_conn *conn;
|
|
||||||
|
|
||||||
/* Drop all items in the list, might be consecutive! */
|
|
||||||
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
|
|
||||||
mgcp_conn_free(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! find a connection by its ID.
|
|
||||||
* \param[in] endp associated endpoint
|
|
||||||
* \param[in] id identification number of the connection
|
|
||||||
* \returns pointer to allocated connection, NULL if not found */
|
|
||||||
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id)
|
|
||||||
{
|
|
||||||
struct mgcp_conn *conn;
|
|
||||||
const char *id_upper;
|
|
||||||
const char *conn_id;
|
|
||||||
|
|
||||||
if (!id || !*id)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Ignore leading zeros in needle */
|
|
||||||
while (*id == '0')
|
|
||||||
id++;
|
|
||||||
|
|
||||||
/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
|
|
||||||
* Connections" defines the id as a hex string, so clients may return lower case hex even though
|
|
||||||
* we sent upper case hex in the CRCX response. */
|
|
||||||
id_upper = osmo_str_toupper(id);
|
|
||||||
|
|
||||||
llist_for_each_entry(conn, &endp->conns, entry) {
|
|
||||||
/* Ignore leading zeros in haystack */
|
|
||||||
for (conn_id = conn->id; *conn_id == '0'; conn_id++);
|
|
||||||
|
|
||||||
if (strcmp(conn_id, id_upper) == 0)
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! get oldest connection in the list.
|
|
||||||
* \param[in] endp associated endpoint */
|
|
||||||
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp)
|
|
||||||
{
|
|
||||||
if (llist_empty(&endp->conns))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! find an RTP connection by its ID.
|
|
||||||
* \param[in] endp associated endpoint
|
|
||||||
* \param[in] id identification number of the connection
|
|
||||||
* \returns pointer to allocated connection, NULL if not found */
|
|
||||||
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
|
|
||||||
const char *id)
|
|
||||||
{
|
|
||||||
struct mgcp_conn *conn;
|
|
||||||
|
|
||||||
conn = mgcp_endp_get_conn(endp, id);
|
|
||||||
if (!conn)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (conn->type == MGCP_CONN_TYPE_RTP)
|
|
||||||
return mgcp_conn_get_conn_rtp(conn);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helps assigning a new lco structure, since "codec" is talloc allocated. */
|
|
||||||
void mgcp_endp_update_lco(struct mgcp_endpoint *endp, const struct mgcp_lco *lco)
|
|
||||||
{
|
|
||||||
/* First free old talloc allocated codec string: */
|
|
||||||
talloc_free(endp->local_options.codec);
|
|
||||||
endp->local_options.codec = NULL;
|
|
||||||
|
|
||||||
if (lco) {
|
|
||||||
endp->local_options = *lco;
|
|
||||||
if (lco->codec)
|
|
||||||
endp->local_options.codec = talloc_strdup(endp, lco->codec);
|
|
||||||
} else {
|
|
||||||
endp->local_options = (struct mgcp_lco){0};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! release endpoint, all open connections are closed.
|
/*! release endpoint, all open connections are closed.
|
||||||
* \param[in] endp endpoint to release */
|
* \param[in] endp endpoint to release */
|
||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||||
@@ -856,7 +665,7 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
|
|||||||
* all connections have been removed already. In case
|
* all connections have been removed already. In case
|
||||||
* that there are still connections open (e.g. when
|
* that there are still connections open (e.g. when
|
||||||
* RSIP is executed), free them all at once. */
|
* RSIP is executed), free them all at once. */
|
||||||
mgcp_endp_free_conn_all(endp);
|
mgcp_conn_free_all(endp);
|
||||||
|
|
||||||
/* We must only decrement the stat item when the endpoint as actually
|
/* We must only decrement the stat item when the endpoint as actually
|
||||||
* claimed. An endpoint is claimed when a call-id is set */
|
* claimed. An endpoint is claimed when a call-id is set */
|
||||||
@@ -867,7 +676,10 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
|
|||||||
/* Reset endpoint parameters and states */
|
/* Reset endpoint parameters and states */
|
||||||
talloc_free(endp->callid);
|
talloc_free(endp->callid);
|
||||||
endp->callid = NULL;
|
endp->callid = NULL;
|
||||||
mgcp_endp_update_lco(endp, 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) {
|
if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
|
||||||
uint8_t ts = e1_ts_nr_from_epname(endp->name);
|
uint8_t ts = e1_ts_nr_from_epname(endp->name);
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||||||
uint8_t *amr_data;
|
uint8_t *amr_data;
|
||||||
struct rtp_hdr *rtp_hdr;
|
struct rtp_hdr *rtp_hdr;
|
||||||
struct amr_hdr *amr_hdr;
|
struct amr_hdr *amr_hdr;
|
||||||
struct mgcp_rtp_codec *dst_codec;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
|
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
|
||||||
@@ -276,8 +275,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||||||
}
|
}
|
||||||
msgb_pull_to_l3(msg);
|
msgb_pull_to_l3(msg);
|
||||||
|
|
||||||
dst_codec = conn_rtp_dst->end.cset.codec;
|
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
|
||||||
if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
|
|
||||||
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
|
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
|
||||||
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
|
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
|
||||||
amr_hdr->cmr = 15; /* no change */
|
amr_hdr->cmr = 15; /* no change */
|
||||||
@@ -305,7 +303,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||||||
.extension = 0,
|
.extension = 0,
|
||||||
.padding = 0,
|
.padding = 0,
|
||||||
.version = 0,
|
.version = 0,
|
||||||
.payload_type = dst_codec->payload_type,
|
.payload_type = conn_rtp_dst->end.codec->payload_type,
|
||||||
.marker = 0,
|
.marker = 0,
|
||||||
.sequence = frame_nr,
|
.sequence = frame_nr,
|
||||||
.timestamp = 0,
|
.timestamp = 0,
|
||||||
@@ -313,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);
|
rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
|
||||||
|
msgb_free(msg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,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);
|
struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
|
||||||
int buflen = msgb_length(msg);
|
int buflen = msgb_length(msg);
|
||||||
char *dest_name;
|
char *dest_name;
|
||||||
int rc;
|
int len;
|
||||||
|
|
||||||
OSMO_ASSERT(conn_src);
|
OSMO_ASSERT(conn_src);
|
||||||
OSMO_ASSERT(conn_dst);
|
OSMO_ASSERT(conn_dst);
|
||||||
@@ -504,10 +503,9 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
|
|||||||
* ignored by the receiver, but still it's useful for debug purposes
|
* ignored by the receiver, but still it's useful for debug purposes
|
||||||
* to set it. Moreover, it seems ip.access nano3g produces much worse
|
* to set it. Moreover, it seems ip.access nano3g produces much worse
|
||||||
* audio output on the air side if timestamp is not set properly. */
|
* audio output on the air side if timestamp is not set properly. */
|
||||||
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
|
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
|
||||||
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
|
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
|
||||||
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
|
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
|
||||||
rtp_state->alt_rtp_tx_sequence++;
|
|
||||||
|
|
||||||
LOGPENDP(endp, DRTP, LOGL_DEBUG,
|
LOGPENDP(endp, DRTP, LOGL_DEBUG,
|
||||||
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
|
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
|
||||||
@@ -515,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));
|
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 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)
|
if (len <= 0)
|
||||||
return rc;
|
return len;
|
||||||
|
|
||||||
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
|
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
|
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
|
||||||
@@ -546,13 +546,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
|||||||
|
|
||||||
msgb_pull_to_l2(msg);
|
msgb_pull_to_l2(msg);
|
||||||
rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
|
rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
|
||||||
/* rtph is further filled in mgcp_send_iuup() below. */
|
/* TODO: fill rtph properly: */
|
||||||
*rtph = (struct rtp_hdr){
|
*rtph = (struct rtp_hdr){
|
||||||
.csrc_count = 0,
|
.csrc_count = 0,
|
||||||
.extension = 0,
|
.extension = 0,
|
||||||
.padding = 0,
|
.padding = 0,
|
||||||
.version = 2,
|
.version = 2,
|
||||||
.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
|
.payload_type = conn_rtp_dst->end.codec->payload_type,
|
||||||
.marker = 0,
|
.marker = 0,
|
||||||
.sequence = 0,
|
.sequence = 0,
|
||||||
.timestamp = 0,
|
.timestamp = 0,
|
||||||
@@ -640,14 +640,13 @@ free_ret:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
|
/* 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)
|
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;
|
struct osmo_iuup_rnl_prim *irp;
|
||||||
struct rtp_hdr *rtph;
|
struct rtp_hdr *rtph;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
int iuup_length = 0;
|
int iuup_length = 0;
|
||||||
struct mgcp_rtp_codec *src_codec;
|
|
||||||
int8_t rfci;
|
int8_t rfci;
|
||||||
|
|
||||||
/* Tx RNL-DATA.req */
|
/* Tx RNL-DATA.req */
|
||||||
@@ -660,14 +659,13 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
|
|||||||
|
|
||||||
/* TODO: CMR handling & multiple frames handling */
|
/* TODO: CMR handling & multiple frames handling */
|
||||||
|
|
||||||
src_codec = conn_src_rtp->end.cset.codec;
|
if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
|
||||||
if (strcmp(src_codec->subtype_name, "AMR") != 0) {
|
|
||||||
LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
|
LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
|
||||||
"Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
|
"Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
|
||||||
src_codec->subtype_name);
|
conn_src_rtp->end.codec->subtype_name);
|
||||||
goto free_ret;
|
goto free_ret;
|
||||||
}
|
}
|
||||||
if (mgcp_codec_amr_is_octet_aligned(src_codec)) {
|
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
|
||||||
struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
|
struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
|
||||||
if (msgb_length(msg) < (sizeof(*amr_hdr))) {
|
if (msgb_length(msg) < (sizeof(*amr_hdr))) {
|
||||||
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
|
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
|
||||||
@@ -753,44 +751,3 @@ int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To be called every time an CRCX/MDCX is received.
|
|
||||||
* returns: 0 if conn can continue, MGCP negative code if an error ocurred during setup */
|
|
||||||
int mgcp_conn_iuup_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn_rtp)
|
|
||||||
{
|
|
||||||
struct mgcp_conn *peer_conn;
|
|
||||||
struct mgcp_conn_rtp *peer_conn_rtp;
|
|
||||||
OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp));
|
|
||||||
|
|
||||||
/* keep waiting to receive remote address through CRCX/MDCX */
|
|
||||||
if (!mgcp_rtp_end_remote_addr_available(&conn_rtp->end))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Conn already IuUP-configured/initialized, nothing to be done. */
|
|
||||||
if (conn_rtp->iuup.configured)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Reached this point, conn_rtp is an IuUP conn which can be configured
|
|
||||||
* and was not yet configured. If its sister conn in the endpoint was
|
|
||||||
* already configured as IuUP "passive", then we know this one can be
|
|
||||||
* configured as IuUP "active" right now. In that case, do so.
|
|
||||||
* This usually happens on an HNBGW co-located MGW, where during
|
|
||||||
* RAB-ASS-REQ the RAN-side conn (sister conn here) was already
|
|
||||||
* configured and then upon rx of RAB-ASS-RESP it sets up (CRCX) the
|
|
||||||
* CN-side IuUP conn (rt_conn here).
|
|
||||||
*/
|
|
||||||
peer_conn = mgcp_find_dst_conn(conn_rtp->conn);
|
|
||||||
/* No peer conn yet, nothing to be done. */
|
|
||||||
if (!peer_conn)
|
|
||||||
return 0;
|
|
||||||
peer_conn_rtp = mgcp_conn_get_conn_rtp(peer_conn);
|
|
||||||
|
|
||||||
if (mgcp_conn_rtp_is_iuup(peer_conn_rtp) &&
|
|
||||||
peer_conn_rtp->iuup.configured &&
|
|
||||||
!conn_rtp->iuup.active_init) {
|
|
||||||
LOG_CONN_RTP(conn_rtp, LOGL_INFO, "Sister IuUP conn in endp configured as passive, init this one as active\n");
|
|
||||||
OSMO_ASSERT(peer_conn_rtp->iuup.init_ind);
|
|
||||||
_conn_iuup_configure_as_active(conn_rtp, peer_conn_rtp->iuup.init_ind);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include <osmocom/mgcp/mgcp.h>
|
#include <osmocom/mgcp/mgcp.h>
|
||||||
#include <osmocom/mgcp/osmux.h>
|
#include <osmocom/mgcp/osmux.h>
|
||||||
@@ -34,10 +33,6 @@
|
|||||||
#include <osmocom/mgcp/mgcp_endp.h>
|
#include <osmocom/mgcp/mgcp_endp.h>
|
||||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||||
|
|
||||||
/* (same fmt as LOGPENDP()) */
|
|
||||||
#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \
|
|
||||||
LOGP(DLMGCP, LEVEL, "%s: endpoint(%s) " FMT, (PDATA)->rq->name, (PDATA)->epname ? : "null-epname", ##ARGS)
|
|
||||||
|
|
||||||
/*! Display an mgcp message on the log output.
|
/*! Display an mgcp message on the log output.
|
||||||
* \param[in] message mgcp message string
|
* \param[in] message mgcp message string
|
||||||
* \param[in] len message mgcp message string length
|
* \param[in] len message mgcp message string length
|
||||||
@@ -81,215 +76,61 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
|
|||||||
|
|
||||||
/*! Parse connection mode.
|
/*! Parse connection mode.
|
||||||
* \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
|
* \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
|
||||||
* \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */
|
* \param[in] endp pointer to endpoint (only used for log output)
|
||||||
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
|
* \param[out] associated connection to be modified accordingly
|
||||||
|
* \returns 0 on success, -1 on error */
|
||||||
|
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
|
||||||
|
struct mgcp_conn *conn)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!mode)
|
if (!mode) {
|
||||||
return MGCP_CONN_NONE;
|
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
|
||||||
|
"missing connection mode\n");
|
||||||
if (strcasecmp(mode, "recvonly") == 0)
|
return -1;
|
||||||
return MGCP_CONN_RECV_ONLY;
|
|
||||||
if (strcasecmp(mode, "sendrecv") == 0)
|
|
||||||
return MGCP_CONN_RECV_SEND;
|
|
||||||
if (strcasecmp(mode, "sendonly") == 0)
|
|
||||||
return MGCP_CONN_SEND_ONLY;
|
|
||||||
if (strcasecmp(mode, "confecho") == 0)
|
|
||||||
return MGCP_CONN_CONFECHO;
|
|
||||||
if (strcasecmp(mode, "loopback") == 0)
|
|
||||||
return MGCP_CONN_LOOPBACK;
|
|
||||||
return MGCP_CONN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Helper function for check_local_cx_options() to get a pointer of the next
|
|
||||||
* lco option identifier
|
|
||||||
* \param[in] lco string
|
|
||||||
* \returns pointer to the beginning of the LCO identifier, NULL on failure */
|
|
||||||
char *get_lco_identifier(const char *options)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
unsigned int count = 0;
|
|
||||||
|
|
||||||
/* Jump to the end of the lco identifier */
|
|
||||||
ptr = strstr(options, ":");
|
|
||||||
if (!ptr)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Walk backwards until the pointer points to the beginning of the
|
|
||||||
* lco identifier. We know that we stand at the beginning when we
|
|
||||||
* are either at the beginning of the memory or see a space or
|
|
||||||
* comma. (this is tolerant, it will accept a:10, b:11 as well as
|
|
||||||
* a:10,b:11) */
|
|
||||||
while (1) {
|
|
||||||
/* Endless loop protection */
|
|
||||||
if (count > 10000)
|
|
||||||
return NULL;
|
|
||||||
else if (ptr < options || *ptr == ' ' || *ptr == ',') {
|
|
||||||
ptr++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr--;
|
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
if (!conn)
|
||||||
/* Check if we got any result */
|
return -1;
|
||||||
if (*ptr == ':')
|
if (!endp)
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Check the LCO option. This function checks for multiple appearance of LCO
|
|
||||||
* options, which is illegal
|
|
||||||
* \param[in] ctx talloc context
|
|
||||||
* \param[in] lco string
|
|
||||||
* \returns 0 on success, -1 on failure */
|
|
||||||
int check_local_cx_options(void *ctx, const char *options)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *options_copy;
|
|
||||||
char *lco_identifier;
|
|
||||||
char *lco_identifier_end;
|
|
||||||
char *next_lco_identifier;
|
|
||||||
|
|
||||||
char **lco_seen;
|
|
||||||
unsigned int lco_seen_n = 0;
|
|
||||||
|
|
||||||
if (!options)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
lco_seen =
|
if (strcasecmp(mode, "recvonly") == 0)
|
||||||
(char **)talloc_zero_size(ctx, strlen(options) * sizeof(char *));
|
conn->mode = MGCP_CONN_RECV_ONLY;
|
||||||
options_copy = talloc_strdup(ctx, options);
|
else if (strcasecmp(mode, "sendrecv") == 0)
|
||||||
lco_identifier = options_copy;
|
conn->mode = MGCP_CONN_RECV_SEND;
|
||||||
|
else if (strcasecmp(mode, "sendonly") == 0)
|
||||||
do {
|
conn->mode = MGCP_CONN_SEND_ONLY;
|
||||||
/* Move the lco_identifier pointer to the beginning of the
|
else if (strcasecmp(mode, "confecho") == 0)
|
||||||
* current lco option identifier */
|
conn->mode = MGCP_CONN_CONFECHO;
|
||||||
lco_identifier = get_lco_identifier(lco_identifier);
|
else if (strcasecmp(mode, "loopback") == 0)
|
||||||
if (!lco_identifier)
|
conn->mode = MGCP_CONN_LOOPBACK;
|
||||||
goto error;
|
else {
|
||||||
|
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
|
||||||
/* Look ahead to the next LCO option early, since we
|
"unknown connection mode: '%s'\n", mode);
|
||||||
* will parse destructively */
|
ret = -1;
|
||||||
next_lco_identifier = strstr(lco_identifier + 1, ",");
|
|
||||||
|
|
||||||
/* Pinch off the end of the lco field identifier name
|
|
||||||
* and see if we still got something, also check if
|
|
||||||
* there is some value after the colon. */
|
|
||||||
lco_identifier_end = strstr(lco_identifier, ":");
|
|
||||||
if (!lco_identifier_end)
|
|
||||||
goto error;
|
|
||||||
if (*(lco_identifier_end + 1) == ' '
|
|
||||||
|| *(lco_identifier_end + 1) == ','
|
|
||||||
|| *(lco_identifier_end + 1) == '\0')
|
|
||||||
goto error;
|
|
||||||
*lco_identifier_end = '\0';
|
|
||||||
if (strlen(lco_identifier) == 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Check if we have already seen the current field identifier
|
|
||||||
* before. If yes, we must bail, an LCO must only appear once
|
|
||||||
* in the LCO string */
|
|
||||||
for (i = 0; i < lco_seen_n; i++) {
|
|
||||||
if (strcasecmp(lco_seen[i], lco_identifier) == 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
lco_seen[lco_seen_n] = lco_identifier;
|
|
||||||
lco_seen_n++;
|
|
||||||
|
|
||||||
/* The first identifier must always be found at the beginnning
|
|
||||||
* of the LCO string */
|
|
||||||
if (lco_seen[0] != options_copy)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Go to the next lco option */
|
|
||||||
lco_identifier = next_lco_identifier;
|
|
||||||
} while (lco_identifier);
|
|
||||||
|
|
||||||
talloc_free(lco_seen);
|
|
||||||
talloc_free(options_copy);
|
|
||||||
return 0;
|
|
||||||
error:
|
|
||||||
talloc_free(lco_seen);
|
|
||||||
talloc_free(options_copy);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the LCO from a string (see RFC 3435).
|
|
||||||
* The string is stored in the 'string' field. A NULL string is handled exactly
|
|
||||||
* like an empty string, the 'string' field is never NULL after this function
|
|
||||||
* has been called. */
|
|
||||||
static int mgcp_parse_lco(void *ctx, struct mgcp_lco *lco, const char *options)
|
|
||||||
{
|
|
||||||
const char *lco_id;
|
|
||||||
char codec[17];
|
|
||||||
char nt[17];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (!options)
|
|
||||||
return 0;
|
|
||||||
if (strlen(options) == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
lco->present = true;
|
|
||||||
|
|
||||||
/* Make sure the encoding of the LCO is consistent before we proceed */
|
|
||||||
if (check_local_cx_options(ctx, options) != 0) {
|
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
|
||||||
"local CX options: Internal inconsistency in Local Connection Options!\n");
|
|
||||||
return -524;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lco_id = options;
|
/* Special handling for RTP connections */
|
||||||
while ((lco_id = get_lco_identifier(lco_id))) {
|
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
||||||
switch (tolower(lco_id[0])) {
|
conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
|
||||||
case 'p':
|
|
||||||
if (sscanf(lco_id + 1, ":%d-%d",
|
|
||||||
&lco->pkt_period_min, &lco->pkt_period_max) == 1)
|
|
||||||
lco->pkt_period_max = lco->pkt_period_min;
|
|
||||||
break;
|
|
||||||
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) {
|
|
||||||
talloc_free(lco->codec);
|
|
||||||
/* MGCP header is case insensive, and we'll need
|
|
||||||
codec in uppercase when using it later: */
|
|
||||||
len = strlen(codec);
|
|
||||||
lco->codec = talloc_size(ctx, len + 1);
|
|
||||||
osmo_str_toupper_buf(lco->codec, len + 1, codec);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
if (lco_id[1] == 't' && sscanf(lco_id + 2, ":%16[^,]", nt) == 1)
|
|
||||||
break;
|
|
||||||
/* else: fall through to print notice log */
|
|
||||||
default:
|
|
||||||
LOGP(DLMGCP, LOGL_NOTICE,
|
|
||||||
"LCO: unhandled option: '%c'/%d in \"%s\"\n",
|
|
||||||
*lco_id, *lco_id, options);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lco_id = strchr(lco_id, ',');
|
|
||||||
if (!lco_id)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGP(DLMGCP, LOGL_DEBUG,
|
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
|
||||||
"local CX options: lco->pkt_period_max: %d, lco->codec: %s\n",
|
|
||||||
lco->pkt_period_max, lco->codec);
|
|
||||||
|
|
||||||
/* Check if the packetization fits the 20ms raster */
|
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
|
||||||
if (lco->pkt_period_min % 20 && lco->pkt_period_max % 20) {
|
mode, conn->mode);
|
||||||
LOGP(DLMGCP, LOGL_ERROR,
|
|
||||||
"local CX options: packetization interval is not a multiple of 20ms!\n");
|
/* Special handling für RTP connections */
|
||||||
return -535;
|
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
||||||
|
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
|
||||||
|
conn->u.rtp.end.output_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
/* The VTY might change the connection mode at any time, so we have
|
||||||
|
* to hold a copy of the original connection mode */
|
||||||
|
conn->mode_orig = conn->mode;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Analyze and parse the the hader of an MGCP messeage string.
|
/*! Analyze and parse the the hader of an MGCP messeage string.
|
||||||
@@ -318,7 +159,8 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (strcasecmp("MGCP", elem)) {
|
if (strcasecmp("MGCP", elem)) {
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
|
LOGP(DLMGCP, LOGL_ERROR,
|
||||||
|
"MGCP header parsing error\n");
|
||||||
return -510;
|
return -510;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -331,121 +173,13 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i != 4) {
|
if (i != 4) {
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n");
|
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
|
||||||
return -510;
|
return -510;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line)
|
|
||||||
{
|
|
||||||
char *saveptr = NULL;
|
|
||||||
|
|
||||||
if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
|
|
||||||
return false;
|
|
||||||
line += strlen(MGCP_X_OSMO_IGN_HEADER);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
char *token = strtok_r(line, " ", &saveptr);
|
|
||||||
line = NULL;
|
|
||||||
if (!token)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!strcasecmp(token, "C"))
|
|
||||||
pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
|
|
||||||
else
|
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Analyze and parse the the header of an MGCP message string.
|
|
||||||
* \param[inout] pdata caller provided memory to store the parsing results.
|
|
||||||
* \returns 0 when parsing was successful, negative (MGCP cause code) on error. */
|
|
||||||
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
|
|
||||||
{
|
|
||||||
struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
|
|
||||||
char *line;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
mgcp_parse_hdr_pars_init(hp);
|
|
||||||
|
|
||||||
for_each_line(line, pdata->save) {
|
|
||||||
if (!mgcp_check_param(line)) {
|
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (toupper(line[0])) {
|
|
||||||
case 'L':
|
|
||||||
hp->lco_string = (const char *)line + 3;
|
|
||||||
rc = mgcp_parse_lco(pdata, &hp->lco, hp->lco_string);
|
|
||||||
if (rc < 0) {
|
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "Invalid LocalConnectionOptions line: '%s'", line);
|
|
||||||
switch (pdata->rq->verb) {
|
|
||||||
case MGCP_VERB_CRCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_crcx_ctr_group,
|
|
||||||
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
|
|
||||||
break;
|
|
||||||
case MGCP_VERB_MDCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_mdcx_ctr_group,
|
|
||||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
hp->callid = (const char *)line + 3;
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
hp->connid = (const char *)line + 3;
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
hp->mode = mgcp_parse_conn_mode((const char *)line + 3);
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
|
|
||||||
hp->remote_osmux_cid = mgcp_parse_osmux_cid(line);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (parse_x_osmo_ign(pdata, line))
|
|
||||||
break;
|
|
||||||
/* Ignore unknown X-headers */
|
|
||||||
break;
|
|
||||||
case '\0':
|
|
||||||
hp->have_sdp = true;
|
|
||||||
goto mgcp_header_done;
|
|
||||||
default:
|
|
||||||
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "unhandled option: '%c'/%d\n", *line, *line);
|
|
||||||
switch (pdata->rq->verb) {
|
|
||||||
case MGCP_VERB_CRCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_crcx_ctr_group,
|
|
||||||
MGCP_CRCX_FAIL_UNHANDLED_PARAM));
|
|
||||||
break;
|
|
||||||
case MGCP_VERB_MDCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_mdcx_ctr_group,
|
|
||||||
MGCP_MDCX_FAIL_UNHANDLED_PARAM));
|
|
||||||
break;
|
|
||||||
case MGCP_VERB_DLCX:
|
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdata->rq->trunk->ratectr.mgcp_dlcx_ctr_group,
|
|
||||||
MGCP_DLCX_FAIL_UNHANDLED_PARAM));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -539;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mgcp_header_done:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
|
/*! Extract OSMUX CID from an MGCP parameter line (string).
|
||||||
* \param[in] line single parameter line from the MGCP message
|
* \param[in] line single parameter line from the MGCP message
|
||||||
* \returns OSMUX CID, -1 wildcard, -2 on error */
|
* \returns OSMUX CID, -1 wildcard, -2 on error */
|
||||||
@@ -456,19 +190,19 @@ int mgcp_parse_osmux_cid(const char *line)
|
|||||||
|
|
||||||
if (strcasecmp(line + 2, "Osmux: *") == 0) {
|
if (strcasecmp(line + 2, "Osmux: *") == 0) {
|
||||||
LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
|
LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
|
||||||
return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
|
if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
|
LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
|
||||||
line);
|
line);
|
||||||
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osmux_cid > OSMUX_CID_MAX) {
|
if (osmux_cid > OSMUX_CID_MAX) {
|
||||||
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
|
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
|
||||||
osmux_cid, OSMUX_CID_MAX);
|
osmux_cid, OSMUX_CID_MAX);
|
||||||
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
|
return -2;
|
||||||
}
|
}
|
||||||
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
|
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
|
||||||
|
|
||||||
@@ -476,13 +210,20 @@ int mgcp_parse_osmux_cid(const char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! Check MGCP parameter line (string) for plausibility.
|
/*! Check MGCP parameter line (string) for plausibility.
|
||||||
|
* \param[in] endp pointer to endpoint (only used for log output, may be NULL)
|
||||||
|
* \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
|
||||||
* \param[in] line single parameter line from the MGCP message
|
* \param[in] line single parameter line from the MGCP message
|
||||||
* \returns true when line seems plausible, false on error */
|
* \returns true when line seems plausible, false on error */
|
||||||
bool mgcp_check_param(const char *line)
|
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
|
||||||
{
|
{
|
||||||
const size_t line_len = strlen(line);
|
const size_t line_len = strlen(line);
|
||||||
if (line[0] != '\0' && line_len < 2)
|
if (line[0] != '\0' && line_len < 2) {
|
||||||
|
if (endp)
|
||||||
|
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
|
||||||
|
else
|
||||||
|
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: A couple more checks wouldn't hurt... */
|
/* FIXME: A couple more checks wouldn't hurt... */
|
||||||
|
|
||||||
@@ -501,6 +242,10 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
|
|||||||
if (!endp)
|
if (!endp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Accept any CallID for "X-Osmo-IGN: C" */
|
||||||
|
if (endp->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!callid)
|
if (!callid)
|
||||||
return -1;
|
return -1;
|
||||||
if (!endp->callid)
|
if (!endp->callid)
|
||||||
@@ -549,7 +294,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if connection exists */
|
/* Check if connection exists */
|
||||||
if (mgcp_endp_get_conn(endp, conn_id))
|
if (mgcp_conn_get(endp, conn_id))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
|
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
|
||||||
* (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
|
* (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.
|
* All rights not specifically granted under this license are reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -14,11 +13,9 @@
|
|||||||
#include <string.h> /* for memcpy */
|
#include <string.h> /* for memcpy */
|
||||||
#include <stdlib.h> /* for abs */
|
#include <stdlib.h> /* for abs */
|
||||||
#include <inttypes.h> /* for PRIu64 */
|
#include <inttypes.h> /* for PRIu64 */
|
||||||
#include <unistd.h> /* for PRIu64 */
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/osmo_io.h>
|
|
||||||
#include <osmocom/core/talloc.h>
|
#include <osmocom/core/talloc.h>
|
||||||
|
|
||||||
#include <osmocom/netif/osmux.h>
|
#include <osmocom/netif/osmux.h>
|
||||||
@@ -33,8 +30,8 @@
|
|||||||
#include <osmocom/mgcp/mgcp_endp.h>
|
#include <osmocom/mgcp/mgcp_endp.h>
|
||||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||||
|
|
||||||
static struct osmo_io_fd *osmux_fd_v4;
|
static struct osmo_fd osmux_fd_v4;
|
||||||
static struct osmo_io_fd *osmux_fd_v6;
|
static struct osmo_fd osmux_fd_v6;
|
||||||
|
|
||||||
static LLIST_HEAD(osmux_handle_list);
|
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)
|
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
|
||||||
{
|
{
|
||||||
struct osmux_handle *handle = data;
|
struct osmux_handle *handle = data;
|
||||||
int rc;
|
socklen_t dest_len;
|
||||||
struct osmo_io_fd *iofd;
|
int rc, fd;
|
||||||
struct mgcp_trunk *trunk = (struct mgcp_trunk *) osmo_iofd_get_data(osmux_fd_v4);
|
struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd_v4.data;
|
||||||
struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
|
struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
|
||||||
|
|
||||||
switch (handle->rem_addr.u.sa.sa_family) {
|
switch (handle->rem_addr.u.sa.sa_family) {
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
iofd = osmux_fd_v6;
|
dest_len = sizeof(handle->rem_addr.u.sin6);
|
||||||
|
fd = osmux_fd_v6.fd;
|
||||||
break;
|
break;
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
default:
|
default:
|
||||||
iofd = osmux_fd_v4;
|
dest_len = sizeof(handle->rem_addr.u.sin);
|
||||||
|
fd = osmux_fd_v4.fd;
|
||||||
break;
|
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) {
|
if (rc < 0) {
|
||||||
char errbuf[129];
|
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",
|
LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n",
|
||||||
osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
|
osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
|
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
|
||||||
msgb_free(batch_msg);
|
|
||||||
} else {
|
} else {
|
||||||
rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_PACKETS_TX_CTR));
|
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. */
|
/* Lookup existing OSMUX handle for specified destination address. */
|
||||||
@@ -204,18 +204,17 @@ osmux_handle_find_or_create(const struct mgcp_trunk *trunk, const struct osmo_so
|
|||||||
return h->in;
|
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] conn associated RTP connection
|
||||||
* \param[in] msg msgb containing an RTP AMR packet
|
* \param[in] msg msgb containing an RTP AMR packet
|
||||||
* \returns 0 on success, -1 on ERROR */
|
* \returns 0 on success, -1 on ERROR */
|
||||||
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
|
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t msg_len;
|
struct msgb *msg2;
|
||||||
|
|
||||||
if (!conn->end.output_enabled) {
|
if (!conn->end.output_enabled) {
|
||||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||||
msgb_free(msg);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,29 +222,30 @@ 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",
|
LOGPCONN(conn->conn, DOSMUX, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
|
||||||
conn->osmux.remote_cid);
|
conn->osmux.remote_cid);
|
||||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||||
msgb_free(msg);
|
|
||||||
return -1;
|
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: */
|
/* 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,
|
LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
|
||||||
"Error converting to AMR octet-aligned mode\n");
|
"Error converting to AMR octet-aligned mode\n");
|
||||||
msgb_free(msg);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_len = msgb_length(msg);
|
while ((ret = osmux_xfrm_input(conn->osmux.in, msg2, conn->osmux.remote_cid)) > 0) {
|
||||||
while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.remote_cid)) > 0) {
|
|
||||||
/* batch full, build and deliver it */
|
/* batch full, build and deliver it */
|
||||||
osmux_xfrm_input_deliver(conn->osmux.in);
|
osmux_xfrm_input_deliver(conn->osmux.in);
|
||||||
}
|
}
|
||||||
/* NOTE: At this point msg is now owned by osmux subsystem and may have been potentially freed. */
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||||
} else {
|
} else {
|
||||||
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
|
rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
|
||||||
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msg_len - sizeof(struct rtp_hdr));
|
rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg2) - sizeof(struct rtp_hdr));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ osmux_conn_lookup(const struct mgcp_trunk *trunk, uint8_t local_cid, const struc
|
|||||||
if (conn->type != MGCP_CONN_TYPE_RTP)
|
if (conn->type != MGCP_CONN_TYPE_RTP)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
conn_rtp = &conn->u.rtp;
|
||||||
if (!mgcp_conn_rtp_is_osmux(conn_rtp))
|
if (!mgcp_conn_rtp_is_osmux(conn_rtp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -325,7 +325,29 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
|
|||||||
};
|
};
|
||||||
|
|
||||||
endp->type->dispatch_rtp_cb(msg);
|
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
|
/* To be called every time some AMR data is received on a connection
|
||||||
@@ -423,16 +445,22 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define osmux_chunk_length(msg, rem) ((rem) - (msg)->len)
|
#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 osmux_hdr *osmuxh;
|
||||||
struct mgcp_trunk *trunk = osmo_iofd_get_data(iofd);
|
struct osmo_sockaddr rem_addr;
|
||||||
struct rate_ctr_group *all_rtp_stats = trunk->ratectr.all_osmux_conn_stats;
|
|
||||||
uint32_t rem;
|
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];
|
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));
|
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) {
|
if (trunk->cfg->osmux.usage == OSMUX_USAGE_OFF) {
|
||||||
LOGP(DOSMUX, LOGL_ERROR,
|
LOGP(DOSMUX, LOGL_ERROR,
|
||||||
@@ -442,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: */
|
/* Catch legacy dummy message and process them separately: */
|
||||||
if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD) {
|
if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD)
|
||||||
osmux_handle_legacy_dummy(trunk, rem_addr, msg);
|
return osmux_handle_legacy_dummy(trunk, &rem_addr, msg);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rem = msg->len;
|
rem = msg->len;
|
||||||
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
||||||
struct mgcp_conn_rtp *conn_src;
|
struct mgcp_conn_rtp *conn_src;
|
||||||
conn_src = osmux_conn_lookup(trunk, osmuxh->circuit_id,
|
conn_src = osmux_conn_lookup(trunk, osmuxh->circuit_id,
|
||||||
rem_addr);
|
&rem_addr);
|
||||||
if (!conn_src) {
|
if (!conn_src) {
|
||||||
LOGP(DOSMUX, LOGL_DEBUG,
|
LOGP(DOSMUX, LOGL_DEBUG,
|
||||||
"Cannot find a src conn for %s CID=%d\n",
|
"Cannot find a src conn for %s CID=%d\n",
|
||||||
@@ -459,7 +485,7 @@ static void osmux_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg
|
|||||||
goto next;
|
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;
|
goto next;
|
||||||
|
|
||||||
mgcp_conn_watchdog_kick(conn_src->conn);
|
mgcp_conn_watchdog_kick(conn_src->conn);
|
||||||
@@ -473,99 +499,58 @@ next:
|
|||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
msgb_free(msg);
|
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 osmux_init(struct mgcp_trunk *trunk)
|
||||||
{
|
{
|
||||||
int ret, fd;
|
int ret;
|
||||||
struct mgcp_config *cfg = trunk->cfg;
|
struct mgcp_config *cfg = trunk->cfg;
|
||||||
|
|
||||||
if (cfg->osmux.initialized)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* So far we only support running on one trunk: */
|
/* So far we only support running on one trunk: */
|
||||||
OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
|
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);
|
osmo_fd_setup(&osmux_fd_v4, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
|
||||||
if (!osmux_fd_v4)
|
osmo_fd_setup(&osmux_fd_v6, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
|
||||||
goto out;
|
|
||||||
osmo_iofd_set_alloc_info(osmux_fd_v4, 4096, 0);
|
|
||||||
|
|
||||||
if (cfg->osmux.local_addr_v4) {
|
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);
|
cfg->endp_dscp, cfg->endp_priority);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
|
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
|
||||||
cfg->osmux.local_addr_v4, cfg->osmux.local_port);
|
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) {
|
if (ret < 0) {
|
||||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", osmo_sock_get_name2(fd));
|
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n",
|
||||||
close(fd);
|
osmo_sock_get_name2(osmux_fd_v4.fd));
|
||||||
goto out_free_v4;
|
return ret;
|
||||||
}
|
}
|
||||||
LOGPTRUNK(trunk, 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) {
|
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);
|
cfg->endp_dscp, cfg->endp_priority);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
|
LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
|
||||||
cfg->osmux.local_addr_v6, cfg->osmux.local_port);
|
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) {
|
if (ret < 0) {
|
||||||
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n", osmo_sock_get_name2(fd));
|
LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n",
|
||||||
close(fd);
|
osmo_sock_get_name2(osmux_fd_v6.fd));
|
||||||
goto out_free_v6;
|
return ret;
|
||||||
}
|
}
|
||||||
LOGPTRUNK(trunk, 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;
|
cfg->osmux.initialized = true;
|
||||||
LOGPTRUNK(trunk, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
|
|
||||||
return 0;
|
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:
|
|
||||||
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! relase OSXMUX cid, that had been allocated to this connection.
|
/*! relase OSXMUX cid, that had been allocated to this connection.
|
||||||
@@ -659,7 +644,7 @@ int conn_osmux_enable(struct mgcp_conn_rtp *conn)
|
|||||||
osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
|
osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
|
||||||
(conn->osmux.remote_cid * rtp_ssrc_winlen) +
|
(conn->osmux.remote_cid * rtp_ssrc_winlen) +
|
||||||
(random() % rtp_ssrc_winlen));
|
(random() % rtp_ssrc_winlen));
|
||||||
osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type);
|
osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.codec->payload_type);
|
||||||
osmux_xfrm_output_set_tx_cb(conn->osmux.out,
|
osmux_xfrm_output_set_tx_cb(conn->osmux.out,
|
||||||
scheduled_from_osmux_tx_rtp_cb, conn);
|
scheduled_from_osmux_tx_rtp_cb, conn);
|
||||||
|
|
||||||
@@ -703,7 +688,7 @@ void conn_osmux_disable(struct mgcp_conn_rtp *conn)
|
|||||||
|
|
||||||
/*! send RTP dummy packet to OSMUX connection port.
|
/*! send RTP dummy packet to OSMUX connection port.
|
||||||
* \param[in] conn associated RTP connection
|
* \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)
|
int osmux_send_dummy(struct mgcp_conn_rtp *conn)
|
||||||
{
|
{
|
||||||
char ipbuf[INET6_ADDRSTRLEN];
|
char ipbuf[INET6_ADDRSTRLEN];
|
||||||
@@ -731,7 +716,7 @@ int osmux_send_dummy(struct mgcp_conn_rtp *conn)
|
|||||||
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
|
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
|
||||||
osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid);
|
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. */
|
/* Keeps track of locally allocated Osmux circuit ID. +7 to round up to 8 bit boundary. */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -93,7 +93,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
|
|||||||
[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
|
[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
|
||||||
[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
|
[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
|
||||||
{ "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
|
{ "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
|
||||||
[MGCP_MDCX_FAIL_BIND_PORT] = { "mdcx:bind_port", "port bind failure." },
|
[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
|
||||||
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
|
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
|
||||||
/*
|
|
||||||
* (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
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/select.h>
|
|
||||||
#include <osmocom/core/socket.h>
|
|
||||||
#include <osmocom/core/osmo_io.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_rtp_end.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_codec.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_conn.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_endp.h>
|
|
||||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
* mgcp_rtp_end
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp)
|
|
||||||
{
|
|
||||||
struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk;
|
|
||||||
struct mgcp_config *cfg = trunk->cfg;
|
|
||||||
|
|
||||||
end->conn_rtp = conn_rtp;
|
|
||||||
end->rtp = NULL;
|
|
||||||
end->rtcp = NULL;
|
|
||||||
memset(&end->addr, 0, sizeof(end->addr));
|
|
||||||
end->rtcp_port = 0;
|
|
||||||
|
|
||||||
/* Set default values */
|
|
||||||
end->frames_per_packet = 0; /* unknown */
|
|
||||||
end->output_enabled = false;
|
|
||||||
end->maximum_packet_time = -1;
|
|
||||||
|
|
||||||
end->force_aligned_timing = trunk->force_aligned_timing;
|
|
||||||
end->force_constant_ssrc = trunk->force_constant_ssrc;
|
|
||||||
end->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
|
|
||||||
|
|
||||||
if (cfg->force_ptime) {
|
|
||||||
end->packet_duration_ms = cfg->force_ptime;
|
|
||||||
end->force_output_ptime = 1;
|
|
||||||
} else {
|
|
||||||
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure codec table is reset */
|
|
||||||
mgcp_codecset_reset(&end->cset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end)
|
|
||||||
{
|
|
||||||
mgcp_rtp_end_free_port(end);
|
|
||||||
mgcp_codecset_reset(&end->cset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms)
|
|
||||||
{
|
|
||||||
if (end->force_output_ptime)
|
|
||||||
return;
|
|
||||||
end->packet_duration_ms = packet_duration_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
|
|
||||||
{
|
|
||||||
return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
|
|
||||||
(osmo_sockaddr_is_any(&rtp_end->addr) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! free allocated RTP and RTCP ports.
|
|
||||||
* \param[in] end RTP end */
|
|
||||||
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end)
|
|
||||||
{
|
|
||||||
if (end->rtp) {
|
|
||||||
osmo_iofd_free(end->rtp);
|
|
||||||
end->rtp = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end->rtcp) {
|
|
||||||
osmo_iofd_free(end->rtcp);
|
|
||||||
end->rtcp = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -199,7 +199,7 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
|
|||||||
unsigned int pt;
|
unsigned int pt;
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
char delimiter;
|
char delimiter;
|
||||||
unsigned int param_val;
|
unsigned int amr_octet_aligned;
|
||||||
|
|
||||||
memset(fmtp_param, 0, sizeof(*fmtp_param));
|
memset(fmtp_param, 0, sizeof(*fmtp_param));
|
||||||
|
|
||||||
@@ -239,30 +239,12 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
|
|||||||
if (delimiter == ';' || delimiter == ',')
|
if (delimiter == ';' || delimiter == ',')
|
||||||
str_ptr[strlen(str_ptr) - 1] = '\0';
|
str_ptr[strlen(str_ptr) - 1] = '\0';
|
||||||
|
|
||||||
/* We support the following codec parameters:
|
/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
|
||||||
*
|
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
|
||||||
* AMR: octet-align parameter of RFC 4867 section 8.3;
|
|
||||||
* FR & EFR: tw-ts-001 parameter, Osmocom private;
|
|
||||||
* HR: tw-ts-002 parameter, Osmocom private.
|
|
||||||
*
|
|
||||||
* tw-ts-001 and tw-ts-002 Osmocom-private parameters are used
|
|
||||||
* only in the context of OsmoBSC driving an E1 MGW endpoint.
|
|
||||||
*/
|
|
||||||
if (sscanf(param_str, "octet-align=%d", ¶m_val) == 1) {
|
|
||||||
fmtp_param->param.amr_octet_aligned_present = true;
|
fmtp_param->param.amr_octet_aligned_present = true;
|
||||||
fmtp_param->param.amr_octet_aligned = false;
|
fmtp_param->param.amr_octet_aligned = false;
|
||||||
if (param_val == 1)
|
if (amr_octet_aligned == 1)
|
||||||
fmtp_param->param.amr_octet_aligned = true;
|
fmtp_param->param.amr_octet_aligned = true;
|
||||||
} else if (sscanf(param_str, "tw-ts-001=%d", ¶m_val) == 1) {
|
|
||||||
fmtp_param->param.fr_efr_twts001_present = true;
|
|
||||||
fmtp_param->param.fr_efr_twts001 = false;
|
|
||||||
if (param_val == 1)
|
|
||||||
fmtp_param->param.fr_efr_twts001 = true;
|
|
||||||
} else if (sscanf(param_str, "tw-ts-002=%d", ¶m_val) == 1) {
|
|
||||||
fmtp_param->param.hr_twts002_present = true;
|
|
||||||
fmtp_param->param.hr_twts002 = false;
|
|
||||||
if (param_val == 1)
|
|
||||||
fmtp_param->param.hr_twts002 = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
param_str = strtok(NULL, " ");
|
param_str = strtok(NULL, " ");
|
||||||
@@ -330,13 +312,16 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! Analyze SDP input string.
|
/*! Analyze SDP input string.
|
||||||
* \param[inout] p provided memory to store the parsing results.
|
* \param[in] endp trunk endpoint.
|
||||||
|
* \param[out] conn associated rtp connection.
|
||||||
|
* \param[out] caller provided memory to store the parsing results.
|
||||||
*
|
*
|
||||||
|
* Note: In conn (conn->end) the function returns the packet duration,
|
||||||
|
* rtp port, rtcp port and the codec information.
|
||||||
* \returns 0 on success, -1 on failure. */
|
* \returns 0 on success, -1 on failure. */
|
||||||
int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
|
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||||
|
struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(p);
|
|
||||||
struct mgcp_parse_sdp *sdp = &p->sdp;
|
|
||||||
struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
|
struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
|
||||||
unsigned int codecs_used = 0;
|
unsigned int codecs_used = 0;
|
||||||
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
|
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
|
||||||
@@ -346,14 +331,19 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
|
|||||||
char *line;
|
char *line;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
void *tmp_ctx = talloc_new(NULL);
|
void *tmp_ctx = talloc_new(NULL);
|
||||||
|
struct mgcp_rtp_end *rtp;
|
||||||
|
|
||||||
int payload_type;
|
int payload_type;
|
||||||
int ptime, ptime2 = 0;
|
int ptime, ptime2 = 0;
|
||||||
char audio_name[64];
|
char audio_name[64];
|
||||||
int port, rc;
|
int port, rc;
|
||||||
|
|
||||||
|
OSMO_ASSERT(endp);
|
||||||
|
OSMO_ASSERT(conn);
|
||||||
|
OSMO_ASSERT(p);
|
||||||
|
|
||||||
|
rtp = &conn->end;
|
||||||
memset(&codecs, 0, sizeof(codecs));
|
memset(&codecs, 0, sizeof(codecs));
|
||||||
mgcp_parse_sdp_init(sdp);
|
|
||||||
|
|
||||||
for_each_line(line, p->save) {
|
for_each_line(line, p->save) {
|
||||||
switch (line[0]) {
|
switch (line[0]) {
|
||||||
@@ -371,19 +361,19 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
|
|||||||
|
|
||||||
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
|
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
|
||||||
if (ptime2 > 0 && ptime2 != ptime)
|
if (ptime2 > 0 && ptime2 != ptime)
|
||||||
sdp->ptime = 0;
|
rtp->packet_duration_ms = 0;
|
||||||
else
|
else
|
||||||
sdp->ptime = ptime;
|
rtp->packet_duration_ms = ptime;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
|
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
|
||||||
sdp->maxptime = ptime2;
|
rtp->maximum_packet_time = ptime2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp("a=fmtp:", line, 6) == 0) {
|
if (strncmp("a=fmtp:", line, 6) == 0) {
|
||||||
rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
|
rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
|
||||||
if (rc >= 0)
|
if (rc >= 0)
|
||||||
fmtp_used++;
|
fmtp_used++;
|
||||||
break;
|
break;
|
||||||
@@ -392,23 +382,33 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
|
|||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
|
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
|
||||||
if (rc == 1)
|
if (rc == 1) {
|
||||||
sdp->rtp_port = port;
|
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
|
||||||
|
rtp->rtcp_port = htons(port + 1);
|
||||||
|
}
|
||||||
|
|
||||||
rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
|
rc = pt_from_sdp(conn->conn, codecs,
|
||||||
|
ARRAY_SIZE(codecs), line);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
codecs_used = rc;
|
codecs_used = rc;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
|
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
|
||||||
talloc_free(tmp_ctx);
|
talloc_free(tmp_ctx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGP(DLMGCP, LOGL_NOTICE,
|
if (endp)
|
||||||
"Unhandled SDP option: '%c'/%d on %s\n",
|
/* TODO: Check spec: We used the bare endpoint number before,
|
||||||
line[0], line[0], p->epname);
|
* now we use the endpoint name as a whole? Is this allowed? */
|
||||||
|
LOGP(DLMGCP, LOGL_NOTICE,
|
||||||
|
"Unhandled SDP option: '%c'/%d on %s\n",
|
||||||
|
line[0], line[0], endp->name);
|
||||||
|
else
|
||||||
|
LOGP(DLMGCP, LOGL_NOTICE,
|
||||||
|
"Unhandled SDP option: '%c'/%d\n",
|
||||||
|
line[0], line[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,22 +422,23 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
|
|||||||
/* Store parsed codec information */
|
/* Store parsed codec information */
|
||||||
for (i = 0; i < codecs_used; i++) {
|
for (i = 0; i < codecs_used; i++) {
|
||||||
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
|
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
|
||||||
rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
|
rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
|
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
talloc_free(tmp_ctx);
|
talloc_free(tmp_ctx);
|
||||||
|
|
||||||
LOGP(DLMGCP, LOGL_NOTICE,
|
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
|
||||||
"%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
|
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
|
||||||
p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
|
osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
|
||||||
|
rtp->packet_duration_ms);
|
||||||
if (codecs_used == 0)
|
if (codecs_used == 0)
|
||||||
LOGPC(DLMGCP, LOGL_NOTICE, "none");
|
LOGPC(DLMGCP, LOGL_NOTICE, "none");
|
||||||
for (i = 0; i < codecs_used; i++) {
|
for (i = 0; i < codecs_used; i++) {
|
||||||
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
|
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
|
||||||
sdp->cset.codecs[i].payload_type,
|
rtp->codecs[i].payload_type,
|
||||||
strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
|
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
|
||||||
LOGPC(DLMGCP, LOGL_NOTICE, " ");
|
LOGPC(DLMGCP, LOGL_NOTICE, " ");
|
||||||
}
|
}
|
||||||
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
|
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
|
||||||
@@ -487,10 +488,34 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add fmtp strings to sdp 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;
|
unsigned int i;
|
||||||
int rc;
|
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++) {
|
for (i = 0; i < fmtp_params_len; i++) {
|
||||||
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
|
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
|
||||||
@@ -507,6 +532,13 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
|
|||||||
return -EINVAL;
|
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");
|
rc = msgb_printf(sdp, "\r\n");
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -526,6 +558,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||||||
const char *addr)
|
const char *addr)
|
||||||
{
|
{
|
||||||
const struct mgcp_rtp_codec *codec;
|
const struct mgcp_rtp_codec *codec;
|
||||||
|
const char *fmtp_extra;
|
||||||
const char *audio_name;
|
const char *audio_name;
|
||||||
int payload_type;
|
int payload_type;
|
||||||
struct sdp_fmtp_param fmtp_param;
|
struct sdp_fmtp_param fmtp_param;
|
||||||
@@ -541,7 +574,10 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||||||
OSMO_ASSERT(sdp);
|
OSMO_ASSERT(sdp);
|
||||||
OSMO_ASSERT(addr);
|
OSMO_ASSERT(addr);
|
||||||
|
|
||||||
codec = conn->end.cset.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;
|
audio_name = codec->audio_name;
|
||||||
payload_type = codec->payload_type;
|
payload_type = codec->payload_type;
|
||||||
@@ -577,29 +613,13 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||||||
goto buffer_too_small;
|
goto buffer_too_small;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include a=fmtp line in MGCP response only for AMR
|
if (codec->param_present) {
|
||||||
* octet-align parameter, not for tw-ts-* parameters.
|
|
||||||
* Rationale:
|
|
||||||
*
|
|
||||||
* - tw-ts-* parameters exist meaningfully only for E1
|
|
||||||
* endpoints driven by OsmoBSC, not in any other
|
|
||||||
* context. libosmo-mgcp-client used by OsmoBSC
|
|
||||||
* completely ignores all fmtp lines, has no code
|
|
||||||
* to parse them at all.
|
|
||||||
*
|
|
||||||
* - The SDP we return is supposed to indicate what
|
|
||||||
* _we_ accept, conceptually independent from what
|
|
||||||
* the remote accepts. And we always accept TW-TS-001
|
|
||||||
* and TW-TS-002 RTP formats going to E1 DL, whether
|
|
||||||
* or not we send them in UL per client request.
|
|
||||||
*/
|
|
||||||
if (codec->param_present && codec->param.amr_octet_aligned_present) {
|
|
||||||
fmtp_param.payload_type = payload_type;
|
fmtp_param.payload_type = payload_type;
|
||||||
fmtp_param.param = codec->param;
|
fmtp_param.param = codec->param;
|
||||||
fmtp_params[0] = fmtp_param;
|
fmtp_params[0] = fmtp_param;
|
||||||
fmtp_params_len = 1;
|
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)
|
if (rc < 0)
|
||||||
goto buffer_too_small;
|
goto buffer_too_small;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
|
|||||||
* keep this option open: */
|
* keep this option open: */
|
||||||
switch (conn->type) {
|
switch (conn->type) {
|
||||||
case MGCP_CONN_TYPE_RTP:
|
case MGCP_CONN_TYPE_RTP:
|
||||||
mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn));
|
mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -306,43 +306,3 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to find a free port by attempting to bind on it. Also handle the
|
|
||||||
* counter that points on the next free port. Since we have a pointer
|
|
||||||
* to the next free port, binding should in work on the first attempt in
|
|
||||||
* general. In case of failure the next port is tried until the whole port
|
|
||||||
* range is tried once. */
|
|
||||||
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct mgcp_port_range *range;
|
|
||||||
unsigned int tries;
|
|
||||||
|
|
||||||
OSMO_ASSERT(trunk);
|
|
||||||
OSMO_ASSERT(conn_rtp);
|
|
||||||
|
|
||||||
range = &trunk->cfg->net_ports;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&range->lock);
|
|
||||||
/* attempt to find a port */
|
|
||||||
tries = (range->range_end - range->range_start) / 2;
|
|
||||||
for (i = 0; i < tries; ++i) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (range->last_port >= range->range_end)
|
|
||||||
range->last_port = range->range_start;
|
|
||||||
|
|
||||||
rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port);
|
|
||||||
|
|
||||||
range->last_port += 2;
|
|
||||||
if (rc == 0) {
|
|
||||||
pthread_mutex_unlock(&range->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&range->lock);
|
|
||||||
LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR,
|
|
||||||
"Allocating a RTP/RTCP port failed %u times.\n", tries);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ static int config_write_mgcp(struct vty *vty)
|
|||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
} else
|
} else
|
||||||
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
|
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",
|
vty_out(vty, " %ssdp audio-payload send-ptime%s",
|
||||||
trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
|
trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
|
||||||
vty_out(vty, " %ssdp audio-payload send-name%s",
|
vty_out(vty, " %ssdp audio-payload send-name%s",
|
||||||
@@ -165,7 +168,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
|
|||||||
{
|
{
|
||||||
struct mgcp_rtp_state *state = &conn->state;
|
struct mgcp_rtp_state *state = &conn->state;
|
||||||
struct mgcp_rtp_end *end = &conn->end;
|
struct mgcp_rtp_end *end = &conn->end;
|
||||||
struct mgcp_rtp_codec *codec = end->cset.codec;
|
struct mgcp_rtp_codec *codec = end->codec;
|
||||||
struct rate_ctr *tx_packets, *tx_bytes;
|
struct rate_ctr *tx_packets, *tx_bytes;
|
||||||
struct rate_ctr *rx_packets, *rx_bytes;
|
struct rate_ctr *rx_packets, *rx_bytes;
|
||||||
struct rate_ctr *dropped_packets;
|
struct rate_ctr *dropped_packets;
|
||||||
@@ -184,7 +187,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
|
|||||||
" Payload Type: %d Rate: %u Channels: %d %s"
|
" Payload Type: %d Rate: %u Channels: %d %s"
|
||||||
" Frame Duration: %u Frame Denominator: %u%s"
|
" Frame Duration: %u Frame Denominator: %u%s"
|
||||||
" FPP: %d Packet Duration: %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",
|
" Output-Enabled: %d Force-PTIME: %d%s",
|
||||||
tx_packets->current, tx_bytes->current, VTY_NEWLINE,
|
tx_packets->current, tx_bytes->current, VTY_NEWLINE,
|
||||||
rx_packets->current, rx_bytes->current, VTY_NEWLINE,
|
rx_packets->current, rx_bytes->current, VTY_NEWLINE,
|
||||||
@@ -195,7 +198,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
|
|||||||
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
|
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
|
||||||
codec->frame_duration_num, codec->frame_duration_den,
|
codec->frame_duration_num, codec->frame_duration_den,
|
||||||
VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
|
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,
|
codec->subtype_name, VTY_NEWLINE, end->output_enabled,
|
||||||
end->force_output_ptime, VTY_NEWLINE);
|
end->force_output_ptime, VTY_NEWLINE);
|
||||||
if (mgcp_conn_rtp_is_osmux(conn)) {
|
if (mgcp_conn_rtp_is_osmux(conn)) {
|
||||||
@@ -254,8 +257,7 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
|
|||||||
* connection types (E1) as soon as
|
* connection types (E1) as soon as
|
||||||
* the implementation is available */
|
* the implementation is available */
|
||||||
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
||||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
dump_rtp_end(vty, &conn->u.rtp);
|
||||||
dump_rtp_end(vty, conn_rtp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -679,15 +681,21 @@ DEFUN_USRATTR(cfg_mgcp_no_rtp_force_ptime,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SDP_STR "SDP File related options\n"
|
DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
|
||||||
#define AUDIO_STR "Audio payload options\n"
|
|
||||||
|
|
||||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_fmtp_extra,
|
|
||||||
cfg_mgcp_sdp_fmtp_extra_cmd,
|
cfg_mgcp_sdp_fmtp_extra_cmd,
|
||||||
|
X(MGW_CMD_ATTR_NEWCONN),
|
||||||
"sdp audio fmtp-extra .NAME",
|
"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 = 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;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -707,6 +715,8 @@ DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SDP_STR "SDP File related options\n"
|
||||||
|
#define AUDIO_STR "Audio payload options\n"
|
||||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
|
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
|
||||||
cfg_mgcp_sdp_payload_number_cmd,
|
cfg_mgcp_sdp_payload_number_cmd,
|
||||||
"sdp audio-payload number <0-255>",
|
"sdp audio-payload number <0-255>",
|
||||||
@@ -857,7 +867,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc,
|
|||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||||
OSMO_ASSERT(trunk);
|
OSMO_ASSERT(trunk);
|
||||||
trunk->force_constant_ssrc = true;
|
trunk->force_constant_ssrc = 1;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,7 +878,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc,
|
|||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||||
OSMO_ASSERT(trunk);
|
OSMO_ASSERT(trunk);
|
||||||
trunk->force_constant_ssrc = false;
|
trunk->force_constant_ssrc = 0;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,7 +933,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp,
|
|||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||||
OSMO_ASSERT(trunk);
|
OSMO_ASSERT(trunk);
|
||||||
trunk->force_constant_ssrc = false;
|
trunk->force_constant_ssrc = 0;
|
||||||
trunk->force_aligned_timing = 0;
|
trunk->force_aligned_timing = 0;
|
||||||
trunk->rfc5993_hr_convert = false;
|
trunk->rfc5993_hr_convert = false;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@@ -1052,17 +1062,28 @@ static int config_write_trunk(struct vty *vty)
|
|||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
} else
|
} else
|
||||||
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN_DEPRECATED(cfg_trunk_sdp_fmtp_extra,
|
DEFUN_USRATTR(cfg_trunk_sdp_fmtp_extra,
|
||||||
cfg_trunk_sdp_fmtp_extra_cmd,
|
cfg_trunk_sdp_fmtp_extra_cmd,
|
||||||
|
X(MGW_CMD_ATTR_NEWCONN),
|
||||||
"sdp audio fmtp-extra .NAME",
|
"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;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,7 +1218,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc,
|
|||||||
"rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
|
"rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
|
||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = vty->index;
|
struct mgcp_trunk *trunk = vty->index;
|
||||||
trunk->force_constant_ssrc = true;
|
trunk->force_constant_ssrc = 1;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1207,7 +1228,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc,
|
|||||||
"no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
|
"no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
|
||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = vty->index;
|
struct mgcp_trunk *trunk = vty->index;
|
||||||
trunk->force_constant_ssrc = false;
|
trunk->force_constant_ssrc = 0;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1257,7 +1278,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp,
|
|||||||
"no rtp-patch", NO_STR RTP_PATCH_STR)
|
"no rtp-patch", NO_STR RTP_PATCH_STR)
|
||||||
{
|
{
|
||||||
struct mgcp_trunk *trunk = vty->index;
|
struct mgcp_trunk *trunk = vty->index;
|
||||||
trunk->force_constant_ssrc = false;
|
trunk->force_constant_ssrc = 0;
|
||||||
trunk->force_aligned_timing = 0;
|
trunk->force_aligned_timing = 0;
|
||||||
trunk->rfc5993_hr_convert = false;
|
trunk->rfc5993_hr_convert = false;
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@@ -1358,11 +1379,10 @@ DEFUN(loop_conn,
|
|||||||
endp = trunk->endpoints[endp_no];
|
endp = trunk->endpoints[endp_no];
|
||||||
int loop = atoi(argv[2]);
|
int loop = atoi(argv[2]);
|
||||||
llist_for_each_entry(conn, &endp->conns, entry) {
|
llist_for_each_entry(conn, &endp->conns, entry) {
|
||||||
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
if (conn->type == MGCP_CONN_TYPE_RTP)
|
||||||
/* Handle it like a MDCX, switch on SSRC patching if enabled */
|
/* Handle it like a MDCX, switch on SSRC patching if enabled */
|
||||||
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
|
mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end);
|
||||||
conn_rtp->state.patch.patch_ssrc = true;
|
else {
|
||||||
} else {
|
|
||||||
/* FIXME: Introduce support for other connection (E1)
|
/* FIXME: Introduce support for other connection (E1)
|
||||||
* types when implementation is available */
|
* types when implementation is available */
|
||||||
vty_out(vty, "%%Can't enable SSRC patching,"
|
vty_out(vty, "%%Can't enable SSRC patching,"
|
||||||
@@ -1420,7 +1440,7 @@ DEFUN(tap_rtp,
|
|||||||
endp = trunk->endpoints[endp_no];
|
endp = trunk->endpoints[endp_no];
|
||||||
|
|
||||||
conn_id = argv[2];
|
conn_id = argv[2];
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
vty_out(vty, "Conn ID %s is invalid.%s",
|
vty_out(vty, "Conn ID %s is invalid.%s",
|
||||||
conn_id, VTY_NEWLINE);
|
conn_id, VTY_NEWLINE);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ osmo_mgw_SOURCES = \
|
|||||||
osmo_mgw_LDADD = \
|
osmo_mgw_LDADD = \
|
||||||
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
||||||
$(LIBOSMOCORE_LIBS) \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
$(LIBOSMOCODEC_LIBS) \
|
|
||||||
$(LIBOSMOVTY_LIBS) \
|
$(LIBOSMOVTY_LIBS) \
|
||||||
$(LIBOSMOGSM_LIBS) \
|
$(LIBOSMOGSM_LIBS) \
|
||||||
$(LIBOSMOCTRL_LIBS) \
|
$(LIBOSMOCTRL_LIBS) \
|
||||||
|
|||||||
@@ -249,6 +249,17 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mgcp_vty_is_config_node(struct vty *vty, int node)
|
||||||
|
{
|
||||||
|
switch (node) {
|
||||||
|
case CONFIG_NODE:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int mgcp_vty_go_parent(struct vty *vty)
|
int mgcp_vty_go_parent(struct vty *vty)
|
||||||
{
|
{
|
||||||
switch (vty->node) {
|
switch (vty->node) {
|
||||||
@@ -258,7 +269,7 @@ int mgcp_vty_go_parent(struct vty *vty)
|
|||||||
break;
|
break;
|
||||||
case MGCP_NODE:
|
case MGCP_NODE:
|
||||||
default:
|
default:
|
||||||
if (vty->node != CONFIG_NODE)
|
if (mgcp_vty_is_config_node(vty, vty->node))
|
||||||
vty->node = CONFIG_NODE;
|
vty->node = CONFIG_NODE;
|
||||||
else
|
else
|
||||||
vty->node = ENABLE_NODE;
|
vty->node = ENABLE_NODE;
|
||||||
@@ -269,36 +280,12 @@ int mgcp_vty_go_parent(struct vty *vty)
|
|||||||
return vty->node;
|
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 = {
|
static struct vty_app_info vty_info = {
|
||||||
.name = "OsmoMGW",
|
.name = "OsmoMGW",
|
||||||
.version = PACKAGE_VERSION,
|
.version = PACKAGE_VERSION,
|
||||||
.go_parent_cb = mgcp_vty_go_parent,
|
.go_parent_cb = mgcp_vty_go_parent,
|
||||||
|
.is_config_node = mgcp_vty_is_config_node,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct log_info_cat log_categories[] = {
|
static const struct log_info_cat log_categories[] = {
|
||||||
@@ -341,8 +328,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
|
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
|
||||||
|
|
||||||
signal(SIGABRT, &signal_handler);
|
|
||||||
signal(SIGUSR1, &signal_handler);
|
|
||||||
osmo_init_ignore_signals();
|
osmo_init_ignore_signals();
|
||||||
osmo_init_logging2(tall_mgw_ctx, &log_info);
|
osmo_init_logging2(tall_mgw_ctx, &log_info);
|
||||||
libosmo_abis_init(tall_mgw_ctx);
|
libosmo_abis_init(tall_mgw_ctx);
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ mgcp_test_SOURCES = \
|
|||||||
mgcp_test_LDADD = \
|
mgcp_test_LDADD = \
|
||||||
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
||||||
$(LIBOSMOCORE_LIBS) \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
$(LIBOSMOCODEC_LIBS) \
|
|
||||||
$(LIBOSMOVTY_LIBS) \
|
$(LIBOSMOVTY_LIBS) \
|
||||||
$(LIBOSMOGSM_LIBS) \
|
$(LIBOSMOGSM_LIBS) \
|
||||||
$(LIBOSMOABIS_LIBS) \
|
$(LIBOSMOABIS_LIBS) \
|
||||||
@@ -46,6 +45,3 @@ mgcp_test_LDADD = \
|
|||||||
$(LIBOSMONETIF_LIBS) \
|
$(LIBOSMONETIF_LIBS) \
|
||||||
-lm \
|
-lm \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
update_exp:
|
|
||||||
$(builddir)/mgcp_test >$(srcdir)/mgcp_test.ok
|
|
||||||
|
|||||||
@@ -43,8 +43,6 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
void *tall_mgw_ctx;
|
|
||||||
|
|
||||||
char *strline_r(char *str, char **saveptr);
|
char *strline_r(char *str, char **saveptr);
|
||||||
|
|
||||||
const char *strline_test_data =
|
const char *strline_test_data =
|
||||||
@@ -105,7 +103,7 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 97\r\n" \
|
"m=audio 16002 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX3A_RET \
|
#define MDCX3A_RET \
|
||||||
"200 18983215 OK\r\n" \
|
"200 18983215 OK\r\n" \
|
||||||
@@ -117,7 +115,7 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 97\r\n" \
|
"m=audio 16002 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX3_FMTP_RET \
|
#define MDCX3_FMTP_RET \
|
||||||
"200 18983215 OK\r\n" \
|
"200 18983215 OK\r\n" \
|
||||||
@@ -129,49 +127,41 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16006 RTP/AVP 97\r\n" \
|
"m=audio 16006 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\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 \
|
#define MDCX4_ADDR0000 \
|
||||||
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: sendrecv\r\n" \
|
"M: sendrecv\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20, a:AMR, nt:IN\r\n" \
|
"L: p:20, a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
|
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
|
||||||
"c=IN IP4 0.0.0.0\r\n" \
|
"c=IN IP4 0.0.0.0\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_ADDR0000_RET \
|
#define MDCX4_ADDR0000_RET \
|
||||||
"200 18983216 OK\r\n" \
|
"527 18983216 FAIL\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"
|
|
||||||
|
|
||||||
#define MDCX4 \
|
#define MDCX4 \
|
||||||
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: sendrecv\r\n" \
|
"M: sendrecv\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20, a:AMR, nt:IN\r\n" \
|
"L: p:20, a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_RET(Ident) \
|
#define MDCX4_RET(Ident) \
|
||||||
"200 " Ident " OK\r\n" \
|
"200 " Ident " OK\r\n" \
|
||||||
@@ -183,7 +173,7 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 99\r\n" \
|
"m=audio 16002 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_RO_RET(Ident) \
|
#define MDCX4_RO_RET(Ident) \
|
||||||
"200 " Ident " OK\r\n" \
|
"200 " Ident " OK\r\n" \
|
||||||
@@ -195,87 +185,87 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 112\r\n" \
|
"m=audio 16002 RTP/AVP 112\r\n" \
|
||||||
"a=rtpmap:112 AMR\r\n" \
|
"a=rtpmap:112 AMR\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_PT1 \
|
#define MDCX4_PT1 \
|
||||||
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: SENDRECV\r\n" \
|
"M: SENDRECV\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20-40, a:AMR, nt:IN\r\n" \
|
"L: p:20-40, a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_PT2 \
|
#define MDCX4_PT2 \
|
||||||
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: sendrecv\r\n" \
|
"M: sendrecv\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20-20, a:AMR, nt:IN\r\n" \
|
"L: p:20-20, a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_PT3 \
|
#define MDCX4_PT3 \
|
||||||
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: sendrecv\r\n" \
|
"M: sendrecv\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: a:AMR, nt:IN\r\n" \
|
"L: a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\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 */
|
/* Test different upper/lower case in options */
|
||||||
#define MDCX4_PT4 \
|
#define MDCX4_PT4 \
|
||||||
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
|
||||||
"m: sendrecv\r\n" \
|
"m: sendrecv\r" \
|
||||||
"c: 2\r\n" \
|
"c: 2\r\n" \
|
||||||
"i: %s\r\n" \
|
"i: %s\r\n" \
|
||||||
"l: A:amr, NT:IN\r\n" \
|
"l: A:amr, NT:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_SO \
|
#define MDCX4_SO \
|
||||||
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: sendonly\r\n" \
|
"M: sendonly\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20, a:AMR, nt:IN\r\n" \
|
"L: p:20, a:AMR, nt:IN\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r\n" \
|
||||||
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
|
||||||
"c=IN IP4 5.6.7.8\r\n" \
|
"c=IN IP4 5.6.7.8\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 4441 RTP/AVP 99\r\n" \
|
"m=audio 4441 RTP/AVP 99\r\n" \
|
||||||
"a=rtpmap:99 AMR/8000\r\n" \
|
"a=rtpmap:99 AMR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define MDCX4_RO \
|
#define MDCX4_RO \
|
||||||
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
|
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
|
||||||
"M: recvonly\r\n" \
|
"M: recvonly\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"I: %s\r\n" \
|
"I: %s\r\n" \
|
||||||
"L: p:20, a:AMR, nt:IN\r\n"
|
"L: p:20, a:AMR, nt:IN\r\n"
|
||||||
@@ -308,7 +298,7 @@ static void test_strline(void)
|
|||||||
"c=IN IP4 123.12.12.123\r\n" \
|
"c=IN IP4 123.12.12.123\r\n" \
|
||||||
"m=audio 5904 RTP/AVP 97\r\n" \
|
"m=audio 5904 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define CRCX_RET \
|
#define CRCX_RET \
|
||||||
"200 2 OK\r\n" \
|
"200 2 OK\r\n" \
|
||||||
@@ -321,7 +311,7 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 97\r\n" \
|
"m=audio 16002 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\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 \
|
#define CRCX_RET_NO_RTPMAP \
|
||||||
"200 2 OK\r\n" \
|
"200 2 OK\r\n" \
|
||||||
@@ -333,7 +323,7 @@ static void test_strline(void)
|
|||||||
"c=IN IP4 0.0.0.0\r\n" \
|
"c=IN IP4 0.0.0.0\r\n" \
|
||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16002 RTP/AVP 97\r\n" \
|
"m=audio 16002 RTP/AVP 97\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define CRCX_FMTP_RET \
|
#define CRCX_FMTP_RET \
|
||||||
"200 2 OK\r\n" \
|
"200 2 OK\r\n" \
|
||||||
@@ -346,17 +336,18 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16006 RTP/AVP 97\r\n" \
|
"m=audio 16006 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\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 \
|
#define CRCX_ZYN \
|
||||||
"CRCX 2 1@mgw MGCP 1.0\r\n" \
|
"CRCX 2 1@mgw MGCP 1.0\r" \
|
||||||
"M: recvonly\r\n" \
|
"M: recvonly\r" \
|
||||||
"C: 2\r\n" \
|
"C: 2\r\n" \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"v=0\r\n" \
|
"v=0\r" \
|
||||||
"c=IN IP4 123.12.12.123\r\n" \
|
"c=IN IP4 123.12.12.123\r" \
|
||||||
"m=audio 5904 RTP/AVP 97\r\n" \
|
"m=audio 5904 RTP/AVP 97\r" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n"
|
"a=rtpmap:97 GSM-EFR/8000\r"
|
||||||
|
|
||||||
#define CRCX_ZYN_RET \
|
#define CRCX_ZYN_RET \
|
||||||
"200 2 OK\r\n" \
|
"200 2 OK\r\n" \
|
||||||
@@ -382,7 +373,7 @@ static void test_strline(void)
|
|||||||
"c=IN IP4 123.12.12.123\r\n" \
|
"c=IN IP4 123.12.12.123\r\n" \
|
||||||
"m=audio 5904 RTP/AVP 97\r\n" \
|
"m=audio 5904 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\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 \
|
#define CRCX_X_OSMO_IGN_RET \
|
||||||
"200 2 OK\r\n" \
|
"200 2 OK\r\n" \
|
||||||
@@ -395,95 +386,7 @@ static void test_strline(void)
|
|||||||
"t=0 0\r\n" \
|
"t=0 0\r\n" \
|
||||||
"m=audio 16010 RTP/AVP 97\r\n" \
|
"m=audio 16010 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\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"
|
|
||||||
|
|
||||||
#define DLCX \
|
#define DLCX \
|
||||||
"DLCX 7 1@mgw MGCP 1.0\r\n" \
|
"DLCX 7 1@mgw MGCP 1.0\r\n" \
|
||||||
@@ -540,7 +443,7 @@ static void test_strline(void)
|
|||||||
"m=audio 5904 RTP/AVP 18 97\r\n" \
|
"m=audio 5904 RTP/AVP 18 97\r\n" \
|
||||||
"a=rtpmap:18 G729/8000\r\n" \
|
"a=rtpmap:18 G729/8000\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/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 \
|
#define CRCX_MULT_2 \
|
||||||
"CRCX 2 2@mgw MGCP 1.0\r\n" \
|
"CRCX 2 2@mgw MGCP 1.0\r\n" \
|
||||||
@@ -555,7 +458,7 @@ static void test_strline(void)
|
|||||||
"a=rtpmap:18 G729/8000\r\n" \
|
"a=rtpmap:18 G729/8000\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=rtpmap:101 FOO/8000\r\n" \
|
"a=rtpmap:101 FOO/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define CRCX_MULT_3 \
|
#define CRCX_MULT_3 \
|
||||||
"CRCX 2 3@mgw MGCP 1.0\r\n" \
|
"CRCX 2 3@mgw MGCP 1.0\r\n" \
|
||||||
@@ -570,7 +473,7 @@ static void test_strline(void)
|
|||||||
"a=rtpmap:18 G729/8000\r\n" \
|
"a=rtpmap:18 G729/8000\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=rtpmap:101 FOO/8000\r\n" \
|
"a=rtpmap:101 FOO/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define CRCX_MULT_4 \
|
#define CRCX_MULT_4 \
|
||||||
"CRCX 2 4@mgw MGCP 1.0\r\n" \
|
"CRCX 2 4@mgw MGCP 1.0\r\n" \
|
||||||
@@ -585,7 +488,7 @@ static void test_strline(void)
|
|||||||
"a=rtpmap:18 G729/8000\r\n" \
|
"a=rtpmap:18 G729/8000\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=rtpmap:101 FOO/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 \
|
#define CRCX_MULT_GSM_EXACT \
|
||||||
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
|
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
|
||||||
@@ -674,7 +577,7 @@ static void test_strline(void)
|
|||||||
"c=IN IP4 123.12.12.123\r\n" \
|
"c=IN IP4 123.12.12.123\r\n" \
|
||||||
"m=audio 5904 RTP/AVP 97\r\n" \
|
"m=audio 5904 RTP/AVP 97\r\n" \
|
||||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||||
"a=ptime:20\r\n"
|
"a=ptime:40\r\n"
|
||||||
|
|
||||||
#define CRCX_NULL_RET "502 2 FAIL\r\n"
|
#define CRCX_NULL_RET "502 2 FAIL\r\n"
|
||||||
|
|
||||||
@@ -683,6 +586,7 @@ struct mgcp_test {
|
|||||||
const char *req;
|
const char *req;
|
||||||
const char *exp_resp;
|
const char *exp_resp;
|
||||||
int ptype;
|
int ptype;
|
||||||
|
const char *extra_fmtp;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mgcp_test tests[] = {
|
static const struct mgcp_test tests[] = {
|
||||||
@@ -710,9 +614,10 @@ static const struct mgcp_test tests[] = {
|
|||||||
{"RQNT1", RQNT, RQNT1_RET},
|
{"RQNT1", RQNT, RQNT1_RET},
|
||||||
{"RQNT2", RQNT2, RQNT2_RET},
|
{"RQNT2", RQNT2, RQNT2_RET},
|
||||||
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
|
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
|
||||||
{"CRCX", CRCX, CRCX_FMTP_RET, 97},
|
{"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
|
||||||
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
|
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
|
||||||
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
|
"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_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
|
||||||
{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_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},
|
{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
|
||||||
@@ -722,11 +627,6 @@ static const struct mgcp_test tests[] = {
|
|||||||
{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
|
{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
|
||||||
{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
|
{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
|
||||||
{"RQNT_NULL", RQNT_NULL, RQNT_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[] = {
|
static const struct mgcp_test retransmit[] = {
|
||||||
@@ -757,13 +657,12 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
|
|||||||
|
|
||||||
static int dummy_packets = 0;
|
static int dummy_packets = 0;
|
||||||
/* override and forward */
|
/* 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 =
|
uint32_t dest_host =
|
||||||
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
|
||||||
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
|
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
|
||||||
const uint8_t *buf = msgb_data(msg);
|
|
||||||
size_t len = msgb_length(msg);
|
|
||||||
|
|
||||||
if (len == sizeof(rtp_dummy_payload)
|
if (len == sizeof(rtp_dummy_payload)
|
||||||
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
|
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
|
||||||
@@ -777,8 +676,6 @@ int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags,
|
|||||||
OSMO_ASSERT(dest_host);
|
OSMO_ASSERT(dest_host);
|
||||||
OSMO_ASSERT(dest_port);
|
OSMO_ASSERT(dest_port);
|
||||||
|
|
||||||
msgb_free(msg);
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -934,6 +831,9 @@ static void test_messages(void)
|
|||||||
|
|
||||||
dummy_packets = 0;
|
dummy_packets = 0;
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
|
||||||
|
t->extra_fmtp);
|
||||||
|
|
||||||
inp = create_msg(t->req, last_conn_id);
|
inp = create_msg(t->req, last_conn_id);
|
||||||
msg = mgcp_handle_message(cfg, inp);
|
msg = mgcp_handle_message(cfg, inp);
|
||||||
msgb_free(inp);
|
msgb_free(inp);
|
||||||
@@ -967,7 +867,7 @@ static void test_messages(void)
|
|||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
|
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, "1");
|
conn = mgcp_conn_get_rtp(endp, "1");
|
||||||
if (conn) {
|
if (conn) {
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
|
|
||||||
@@ -1025,14 +925,14 @@ static void test_messages(void)
|
|||||||
fprintf(stderr, "endpoint:%s: "
|
fprintf(stderr, "endpoint:%s: "
|
||||||
"payload type %d (expected %d)\n",
|
"payload type %d (expected %d)\n",
|
||||||
last_endpoint,
|
last_endpoint,
|
||||||
conn->end.cset.codec->payload_type, t->ptype);
|
conn->end.codec->payload_type, t->ptype);
|
||||||
|
|
||||||
if (t->ptype != PTYPE_IGNORE)
|
if (t->ptype != PTYPE_IGNORE)
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type ==
|
OSMO_ASSERT(conn->end.codec->payload_type ==
|
||||||
t->ptype);
|
t->ptype);
|
||||||
|
|
||||||
/* Reset them again for next test */
|
/* Reset them again for next test */
|
||||||
conn->end.cset.codec->payload_type = PTYPE_NONE;
|
conn->end.codec->payload_type = PTYPE_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,9 +1110,7 @@ static void test_packet_loss_calc(void)
|
|||||||
_conn =
|
_conn =
|
||||||
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
|
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
|
||||||
"test-connection");
|
"test-connection");
|
||||||
OSMO_ASSERT(_conn);
|
conn = mgcp_conn_get_rtp(&endp, _conn->id);
|
||||||
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
|
|
||||||
OSMO_ASSERT(conn);
|
|
||||||
state = &conn->state;
|
state = &conn->state;
|
||||||
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
||||||
|
|
||||||
@@ -1232,7 +1130,7 @@ static void test_packet_loss_calc(void)
|
|||||||
pl_test_dat[i].expected);
|
pl_test_dat[i].expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
mgcp_endp_free_conn_all(&endp);
|
mgcp_conn_free_all(&endp);
|
||||||
}
|
}
|
||||||
|
|
||||||
talloc_free(trunk);
|
talloc_free(trunk);
|
||||||
@@ -1463,13 +1361,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
|
|||||||
_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
|
_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
|
||||||
"test-connection");
|
"test-connection");
|
||||||
OSMO_ASSERT(_conn);
|
OSMO_ASSERT(_conn);
|
||||||
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
|
conn = mgcp_conn_get_rtp(&endp, _conn->id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
|
|
||||||
rtp = &conn->end;
|
rtp = &conn->end;
|
||||||
|
|
||||||
OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
|
OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
|
||||||
rtp->cset.codec = &rtp->cset.codecs[0];
|
rtp->codec = &rtp->codecs[0];
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
|
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
|
||||||
struct rtp_packet_info *info = test_rtp_packets1 + i;
|
struct rtp_packet_info *info = test_rtp_packets1 + i;
|
||||||
@@ -1481,6 +1379,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
|
|||||||
OSMO_ASSERT(info->len >= 0);
|
OSMO_ASSERT(info->len >= 0);
|
||||||
msg->l3h = msgb_put(msg, info->len);
|
msg->l3h = msgb_put(msg, info->len);
|
||||||
memcpy((char*)msgb_l3(msg), info->data, info->len);
|
memcpy((char*)msgb_l3(msg), info->data, info->len);
|
||||||
|
mgcp_rtp_end_config(&endp, 1, rtp);
|
||||||
|
|
||||||
mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
|
mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
|
||||||
|
|
||||||
@@ -1514,7 +1413,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
force_monotonic_time_us = -1;
|
force_monotonic_time_us = -1;
|
||||||
mgcp_endp_free_conn_all(&endp);
|
mgcp_conn_free_all(&endp);
|
||||||
talloc_free(trunk);
|
talloc_free(trunk);
|
||||||
talloc_free(cfg);
|
talloc_free(cfg);
|
||||||
}
|
}
|
||||||
@@ -1549,9 +1448,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
|
OSMO_ASSERT(conn->end.codec->payload_type == 18);
|
||||||
|
|
||||||
/* Allocate 2@mgw with three codecs, last one ignored */
|
/* Allocate 2@mgw with three codecs, last one ignored */
|
||||||
last_endpoint[0] = '\0';
|
last_endpoint[0] = '\0';
|
||||||
@@ -1565,9 +1464,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
|
OSMO_ASSERT(conn->end.codec->payload_type == 18);
|
||||||
|
|
||||||
/* Allocate 3@mgw with no codecs, check for PT == 0 */
|
/* Allocate 3@mgw with no codecs, check for PT == 0 */
|
||||||
/* Note: It usually makes no sense to leave the payload type list
|
/* Note: It usually makes no sense to leave the payload type list
|
||||||
@@ -1586,9 +1485,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
|
OSMO_ASSERT(conn->end.codec->payload_type == 0);
|
||||||
|
|
||||||
/* Allocate 4@mgw with a single codec */
|
/* Allocate 4@mgw with a single codec */
|
||||||
last_endpoint[0] = '\0';
|
last_endpoint[0] = '\0';
|
||||||
@@ -1602,9 +1501,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
|
OSMO_ASSERT(conn->end.codec->payload_type == 18);
|
||||||
|
|
||||||
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
|
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
|
||||||
last_endpoint[0] = '\0';
|
last_endpoint[0] = '\0';
|
||||||
@@ -1618,9 +1517,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
|
OSMO_ASSERT(conn->end.codec->payload_type == 0);
|
||||||
|
|
||||||
inp = create_msg(MDCX_NAT_DUMMY, conn_id);
|
inp = create_msg(MDCX_NAT_DUMMY, conn_id);
|
||||||
last_endpoint[0] = '\0';
|
last_endpoint[0] = '\0';
|
||||||
@@ -1630,9 +1529,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 3);
|
OSMO_ASSERT(conn->end.codec->payload_type == 3);
|
||||||
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
|
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
inet_aton("8.8.8.8", &addr);
|
inet_aton("8.8.8.8", &addr);
|
||||||
@@ -1647,7 +1546,7 @@ static void test_multilple_codec(void)
|
|||||||
talloc_free(endp->last_response);
|
talloc_free(endp->last_response);
|
||||||
talloc_free(endp->last_trans);
|
talloc_free(endp->last_trans);
|
||||||
endp->last_response = endp->last_trans = NULL;
|
endp->last_response = endp->last_trans = NULL;
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(!conn);
|
OSMO_ASSERT(!conn);
|
||||||
|
|
||||||
last_endpoint[0] = '\0';
|
last_endpoint[0] = '\0';
|
||||||
@@ -1661,9 +1560,9 @@ static void test_multilple_codec(void)
|
|||||||
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
|
||||||
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
|
||||||
OSMO_ASSERT(endp);
|
OSMO_ASSERT(endp);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
|
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
|
OSMO_ASSERT(conn->end.codec->payload_type == 0);
|
||||||
|
|
||||||
mgcp_endpoints_release(trunk);
|
mgcp_endpoints_release(trunk);
|
||||||
talloc_free(cfg);
|
talloc_free(cfg);
|
||||||
@@ -1690,7 +1589,7 @@ static void test_no_cycle(void)
|
|||||||
_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
|
_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
|
||||||
"test-connection");
|
"test-connection");
|
||||||
OSMO_ASSERT(_conn);
|
OSMO_ASSERT(_conn);
|
||||||
conn = mgcp_endp_get_conn_rtp(endp, _conn->id);
|
conn = mgcp_conn_get_rtp(endp, _conn->id);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
|
|
||||||
OSMO_ASSERT(conn->state.stats.initialized == 0);
|
OSMO_ASSERT(conn->state.stats.initialized == 0);
|
||||||
@@ -2196,7 +2095,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
|
|||||||
int payload_type_conn_dst;
|
int payload_type_conn_dst;
|
||||||
|
|
||||||
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
|
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
|
||||||
if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
|
if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
|
||||||
if (expect->payload_type_map[index_conn_src] == -EINVAL
|
if (expect->payload_type_map[index_conn_src] == -EINVAL
|
||||||
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
|
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
|
||||||
printf(" codec decision failed (expected)!\n");
|
printf(" codec decision failed (expected)!\n");
|
||||||
@@ -2206,19 +2105,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf(" Codec decision result:\n");
|
printf(" Codec decision result:\n");
|
||||||
if (conn[index_conn_src].end.cset.codec) {
|
if (conn[index_conn_src].end.codec) {
|
||||||
payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
|
payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
|
||||||
printf(" conn[%u]: codec:%s, pt:%d\n",
|
printf(" conn[%u]: codec:%s, pt:%d\n",
|
||||||
index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src);
|
index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
|
||||||
} else {
|
} else {
|
||||||
payload_type_conn_src = -EINVAL;
|
payload_type_conn_src = -EINVAL;
|
||||||
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
|
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn[index_conn_dst].end.cset.codec) {
|
if (conn[index_conn_dst].end.codec) {
|
||||||
payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
|
payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
|
||||||
printf(" conn[%u]: codec:%s, pt:%d\n",
|
printf(" conn[%u]: codec:%s, pt:%d\n",
|
||||||
index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name,
|
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
|
||||||
payload_type_conn_dst);
|
payload_type_conn_dst);
|
||||||
} else {
|
} else {
|
||||||
payload_type_conn_dst = -EINVAL;
|
payload_type_conn_dst = -EINVAL;
|
||||||
@@ -2245,7 +2144,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
|
|||||||
static void test_mgcp_codec_decide(void)
|
static void test_mgcp_codec_decide(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
bool ok_all = true;
|
bool ok = true;
|
||||||
printf("\nTesting mgcp_codec_find_convertible()\n");
|
printf("\nTesting mgcp_codec_find_convertible()\n");
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
|
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
|
||||||
@@ -2254,7 +2153,6 @@ static void test_mgcp_codec_decide(void)
|
|||||||
int rc;
|
int rc;
|
||||||
int conn_i;
|
int conn_i;
|
||||||
int c;
|
int c;
|
||||||
bool ok = true;
|
|
||||||
|
|
||||||
printf("#%d: %s\n", i, t->descr);
|
printf("#%d: %s\n", i, t->descr);
|
||||||
|
|
||||||
@@ -2266,8 +2164,8 @@ static void test_mgcp_codec_decide(void)
|
|||||||
if (!codec->audio_name)
|
if (!codec->audio_name)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, codec->payload_type,
|
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
|
||||||
codec->audio_name, codec->param);
|
codec->param);
|
||||||
|
|
||||||
printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
|
printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
|
||||||
codec->param ?
|
codec->param ?
|
||||||
@@ -2295,12 +2193,9 @@ static void test_mgcp_codec_decide(void)
|
|||||||
printf(" ===> SUCCESS: codec decision as expected!\n");
|
printf(" ===> SUCCESS: codec decision as expected!\n");
|
||||||
else
|
else
|
||||||
printf(" ===> FAIL: unexpected codec decision!\n");
|
printf(" ===> FAIL: unexpected codec decision!\n");
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
ok_all = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OSMO_ASSERT(ok_all);
|
OSMO_ASSERT(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_conn_id_matching(void)
|
void test_conn_id_matching(void)
|
||||||
@@ -2325,7 +2220,7 @@ void test_conn_id_matching(void)
|
|||||||
|
|
||||||
INIT_LLIST_HEAD(&endp.conns);
|
INIT_LLIST_HEAD(&endp.conns);
|
||||||
|
|
||||||
conn = talloc_zero(tall_mgw_ctx, struct mgcp_conn);
|
conn = talloc_zero(NULL, struct mgcp_conn);
|
||||||
OSMO_ASSERT(conn);
|
OSMO_ASSERT(conn);
|
||||||
osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
|
osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
|
||||||
llist_add(&conn->entry, &endp.conns);
|
llist_add(&conn->entry, &endp.conns);
|
||||||
@@ -2333,7 +2228,7 @@ void test_conn_id_matching(void)
|
|||||||
for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
|
for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
|
||||||
const char *needle = conn_id_request[i];
|
const char *needle = conn_id_request[i];
|
||||||
printf("needle='%s' ", needle);
|
printf("needle='%s' ", needle);
|
||||||
conn_match = mgcp_endp_get_conn(&endp, needle);
|
conn_match = mgcp_conn_get(&endp, needle);
|
||||||
OSMO_ASSERT(conn_match);
|
OSMO_ASSERT(conn_match);
|
||||||
printf("found '%s'\n", conn_match->id);
|
printf("found '%s'\n", conn_match->id);
|
||||||
OSMO_ASSERT(conn_match == conn);
|
OSMO_ASSERT(conn_match == conn);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ v=0
|
|||||||
c=IN IP4 123.12.12.123
|
c=IN IP4 123.12.12.123
|
||||||
m=audio 5904 RTP/AVP 97
|
m=audio 5904 RTP/AVP 97
|
||||||
a=rtpmap:97 GSM-EFR/8000
|
a=rtpmap:97 GSM-EFR/8000
|
||||||
a=ptime:20
|
a=ptime:40
|
||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
checking response:
|
checking response:
|
||||||
@@ -101,42 +101,40 @@ Testing MDCX4_ADDR000
|
|||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
MDCX 18983216 1@mgw MGCP 1.0
|
MDCX 18983216 1@mgw MGCP 1.0
|
||||||
M: sendrecv
|
M: sendrecv
|
||||||
C: 2
|
|
||||||
C: 2
|
C: 2
|
||||||
I: %s
|
I: %s
|
||||||
|
L: p:20, a:AMR, nt:IN
|
||||||
|
|
||||||
v=0
|
v=0
|
||||||
o=- %s 23 IN IP4 0.0.0.0
|
o=- %s 23 IN IP4 0.0.0.0
|
||||||
c=IN IP4 0.0.0.0
|
c=IN IP4 0.0.0.0
|
||||||
t=0 0
|
t=0 0
|
||||||
m=audio 4441 RTP/AVP 99
|
m=audio 4441 RTP/AVP 99
|
||||||
a=ptime:20
|
a=rtpmap:99 AMR/8000
|
||||||
a=ptime:40
|
a=ptime:40
|
||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
using message with patched conn_id for comparison
|
checking response:
|
||||||
using message as statically defined for comparison
|
using message as statically defined for comparison
|
||||||
(response contains a connection id)
|
Response matches our expectations.
|
||||||
(response does not contain a connection id)
|
(response does not contain a connection id)
|
||||||
|
|
||||||
================================================
|
================================================
|
||||||
Testing MDCX4
|
Testing MDCX4
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
M: sendrecv
|
MDCX 18983217 1@mgw MGCP 1.0
|
||||||
C: 2
|
|
||||||
M: sendrecv
|
M: sendrecv
|
||||||
C: 2
|
C: 2
|
||||||
|
I: %s
|
||||||
L: p:20, a:AMR, nt:IN
|
L: p:20, a:AMR, nt:IN
|
||||||
|
|
||||||
v=0
|
v=0
|
||||||
o=- %s 23 IN IP4 5.6.7.8
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
c=IN IP4 5.6.7.8
|
c=IN IP4 5.6.7.8
|
||||||
t=0 0
|
t=0 0
|
||||||
a=ptime:20
|
m=audio 4441 RTP/AVP 99
|
||||||
a=rtpmap:99 AMR/8000
|
a=rtpmap:99 AMR/8000
|
||||||
a=ptime:40
|
a=ptime:40
|
||||||
|
|
||||||
@@ -150,18 +148,17 @@ Testing MDCX4_PT1
|
|||||||
================================================
|
================================================
|
||||||
Testing MDCX4_PT1
|
Testing MDCX4_PT1
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
M: SENDRECV
|
---------8<---------
|
||||||
C: 2
|
|
||||||
MDCX 18983218 1@mgw MGCP 1.0
|
MDCX 18983218 1@mgw MGCP 1.0
|
||||||
M: SENDRECV
|
M: SENDRECV
|
||||||
|
C: 2
|
||||||
I: %s
|
I: %s
|
||||||
L: p:20-40, a:AMR, nt:IN
|
L: p:20-40, a:AMR, nt:IN
|
||||||
|
|
||||||
v=0
|
v=0
|
||||||
o=- %s 23 IN IP4 5.6.7.8
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
c=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
|
m=audio 4441 RTP/AVP 99
|
||||||
a=rtpmap:99 AMR/8000
|
a=rtpmap:99 AMR/8000
|
||||||
a=ptime:40
|
a=ptime:40
|
||||||
@@ -175,18 +172,17 @@ Testing MDCX4_PT2
|
|||||||
|
|
||||||
================================================
|
================================================
|
||||||
Testing MDCX4_PT2
|
Testing MDCX4_PT2
|
||||||
M: sendrecv
|
creating message from statically defined input:
|
||||||
C: 2
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
MDCX 18983219 1@mgw MGCP 1.0
|
MDCX 18983219 1@mgw MGCP 1.0
|
||||||
|
M: sendrecv
|
||||||
C: 2
|
C: 2
|
||||||
I: %s
|
I: %s
|
||||||
L: p:20-20, a:AMR, nt:IN
|
L: p:20-20, a:AMR, nt:IN
|
||||||
|
|
||||||
v=0
|
v=0
|
||||||
o=- %s 23 IN IP4 5.6.7.8
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
a=ptime:20
|
c=IN IP4 5.6.7.8
|
||||||
t=0 0
|
t=0 0
|
||||||
m=audio 4441 RTP/AVP 99
|
m=audio 4441 RTP/AVP 99
|
||||||
a=rtpmap:99 AMR/8000
|
a=rtpmap:99 AMR/8000
|
||||||
@@ -200,18 +196,17 @@ Testing MDCX4_PT3
|
|||||||
Dummy packets: 2
|
Dummy packets: 2
|
||||||
|
|
||||||
================================================
|
================================================
|
||||||
M: sendrecv
|
Testing MDCX4_PT3
|
||||||
C: 2
|
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
|
MDCX 18983220 1@mgw MGCP 1.0
|
||||||
M: sendrecv
|
M: sendrecv
|
||||||
C: 2
|
C: 2
|
||||||
I: %s
|
I: %s
|
||||||
L: a:AMR, nt:IN
|
L: a:AMR, nt:IN
|
||||||
|
|
||||||
v=0
|
v=0
|
||||||
a=ptime:20
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
c=IN IP4 5.6.7.8
|
c=IN IP4 5.6.7.8
|
||||||
t=0 0
|
t=0 0
|
||||||
m=audio 4441 RTP/AVP 99
|
m=audio 4441 RTP/AVP 99
|
||||||
@@ -225,18 +220,17 @@ Testing MDCX4_PT4
|
|||||||
(response contains a connection id)
|
(response contains a connection id)
|
||||||
Dummy packets: 2
|
Dummy packets: 2
|
||||||
|
|
||||||
m: sendrecv
|
================================================
|
||||||
c: 2
|
|
||||||
Testing MDCX4_PT4
|
Testing MDCX4_PT4
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
|
---------8<---------
|
||||||
MDCX 18983221 1@mgw MGCP 1.0
|
MDCX 18983221 1@mgw MGCP 1.0
|
||||||
m: sendrecv
|
m: sendrecv
|
||||||
c: 2
|
c: 2
|
||||||
i: %s
|
i: %s
|
||||||
l: A:amr, NT:IN
|
l: A:amr, NT:IN
|
||||||
|
|
||||||
a=ptime:20
|
v=0
|
||||||
o=- %s 23 IN IP4 5.6.7.8
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
c=IN IP4 5.6.7.8
|
c=IN IP4 5.6.7.8
|
||||||
t=0 0
|
t=0 0
|
||||||
@@ -250,18 +244,17 @@ Testing MDCX4_SO
|
|||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
(response contains a connection id)
|
(response contains a connection id)
|
||||||
Dummy packets: 2
|
Dummy packets: 2
|
||||||
M: sendonly
|
|
||||||
C: 2
|
|
||||||
================================================
|
================================================
|
||||||
Testing MDCX4_SO
|
Testing MDCX4_SO
|
||||||
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
MDCX 18983222 1@mgw MGCP 1.0
|
MDCX 18983222 1@mgw MGCP 1.0
|
||||||
M: sendonly
|
M: sendonly
|
||||||
C: 2
|
C: 2
|
||||||
I: %s
|
I: %s
|
||||||
L: p:20, a:AMR, nt:IN
|
L: p:20, a:AMR, nt:IN
|
||||||
a=ptime:20
|
|
||||||
v=0
|
v=0
|
||||||
o=- %s 23 IN IP4 5.6.7.8
|
o=- %s 23 IN IP4 5.6.7.8
|
||||||
c=IN IP4 5.6.7.8
|
c=IN IP4 5.6.7.8
|
||||||
@@ -274,8 +267,7 @@ Testing MDCX4_RO
|
|||||||
checking response:
|
checking response:
|
||||||
using message with patched conn_id for comparison
|
using message with patched conn_id for comparison
|
||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
M: recvonly
|
(response contains a connection id)
|
||||||
C: 2
|
|
||||||
|
|
||||||
================================================
|
================================================
|
||||||
Testing MDCX4_RO
|
Testing MDCX4_RO
|
||||||
@@ -304,15 +296,9 @@ Response matches our expectations.
|
|||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
checking response:
|
checking response:
|
||||||
CRCX 2 1@mgw MGCP 1.0
|
using message as statically defined for comparison
|
||||||
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
|
|
||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
|
(response does not contain a connection id)
|
||||||
|
|
||||||
================================================
|
================================================
|
||||||
Testing CRCX_ZYN
|
Testing CRCX_ZYN
|
||||||
@@ -428,7 +414,7 @@ v=0
|
|||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
(response does not contain a connection id)
|
(response does not contain a connection id)
|
||||||
|
|
||||||
a=ptime:20
|
================================================
|
||||||
Testing CRCX
|
Testing CRCX
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -493,7 +479,7 @@ v=0
|
|||||||
(response contains a connection id)
|
(response contains a connection id)
|
||||||
|
|
||||||
================================================
|
================================================
|
||||||
a=ptime:20
|
Testing CRCX
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
CRCX 2 1@mgw MGCP 1.0
|
CRCX 2 1@mgw MGCP 1.0
|
||||||
@@ -564,7 +550,7 @@ v=0
|
|||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
(response does not contain a connection id)
|
(response does not contain a connection id)
|
||||||
|
|
||||||
a=ptime:20
|
================================================
|
||||||
Testing CRCX_NULL
|
Testing CRCX_NULL
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -613,110 +599,6 @@ using message as statically defined for comparison
|
|||||||
(response does not contain a connection id)
|
(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)
|
|
||||||
|
|
||||||
Testing RQNT_NULL
|
Testing RQNT_NULL
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -730,7 +612,7 @@ v=0
|
|||||||
Response matches our expectations.
|
Response matches our expectations.
|
||||||
(response does not contain a connection id)
|
(response does not contain a connection id)
|
||||||
|
|
||||||
a=ptime:20
|
================================================
|
||||||
Testing CRCX
|
Testing CRCX
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -748,7 +630,7 @@ v=0
|
|||||||
---------8<---------
|
---------8<---------
|
||||||
checking response:
|
checking response:
|
||||||
using message with patched conn_id for comparison
|
using message with patched conn_id for comparison
|
||||||
a=ptime:20
|
Response matches our expectations.
|
||||||
Re-transmitting CRCX
|
Re-transmitting CRCX
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -860,7 +742,7 @@ v=0
|
|||||||
---------8<---------
|
---------8<---------
|
||||||
checking response:
|
checking response:
|
||||||
using message as statically defined for comparison
|
using message as statically defined for comparison
|
||||||
a=ptime:20
|
Response matches our expectations.
|
||||||
Testing packet loss calculation.
|
Testing packet loss calculation.
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
@@ -1314,7 +1196,7 @@ c=IN IP4 123.12.12.123
|
|||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||||
Stats: Jitter = 5, Transit = -163760
|
Stats: Jitter = 5, Transit = -163760
|
||||||
Testing multiple payload types
|
Testing multiple payload types
|
||||||
a=ptime:20
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
CRCX 2 1@mgw MGCP 1.0
|
CRCX 2 1@mgw MGCP 1.0
|
||||||
M: recvonly
|
M: recvonly
|
||||||
@@ -1331,7 +1213,7 @@ m=audio 5904 RTP/AVP 18 97 101
|
|||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
a=ptime:20
|
---------8<---------
|
||||||
CRCX 2 2@mgw MGCP 1.0
|
CRCX 2 2@mgw MGCP 1.0
|
||||||
M: recvonly
|
M: recvonly
|
||||||
C: 2
|
C: 2
|
||||||
@@ -1348,7 +1230,7 @@ m=audio 5904 RTP/AVP
|
|||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
a=ptime:20
|
---------8<---------
|
||||||
CRCX 2 3@mgw MGCP 1.0
|
CRCX 2 3@mgw MGCP 1.0
|
||||||
M: recvonly
|
M: recvonly
|
||||||
C: 2
|
C: 2
|
||||||
@@ -1365,7 +1247,7 @@ m=audio 5904 RTP/AVP 18
|
|||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
a=ptime:20
|
---------8<---------
|
||||||
CRCX 2 4@mgw MGCP 1.0
|
CRCX 2 4@mgw MGCP 1.0
|
||||||
M: recvonly
|
M: recvonly
|
||||||
C: 2
|
C: 2
|
||||||
@@ -1447,7 +1329,7 @@ v=0
|
|||||||
a=recvonly
|
a=recvonly
|
||||||
|
|
||||||
---------8<---------
|
---------8<---------
|
||||||
a=ptime:20
|
Testing no sequence flow on initial packet
|
||||||
Testing no rtpmap name
|
Testing no rtpmap name
|
||||||
creating message from statically defined input:
|
creating message from statically defined input:
|
||||||
---------8<---------
|
---------8<---------
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ void test_response_cb(struct mgcp_response *response, void *priv)
|
|||||||
printf(" audio_port = %u\n", response->audio_port);
|
printf(" audio_port = %u\n", response->audio_port);
|
||||||
printf(" audio_ip = %s\n", response->audio_ip);
|
printf(" audio_ip = %s\n", response->audio_ip);
|
||||||
printf(" ptime = %u\n", response->ptime);
|
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);
|
printf(" ptmap_len = %u\n", response->ptmap_len);
|
||||||
for(i=0;i<response->ptmap_len;i++) {
|
for(i=0;i<response->ptmap_len;i++) {
|
||||||
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
|
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
|
||||||
@@ -146,11 +149,12 @@ void test_mgcp_msg(void)
|
|||||||
.conn_id = "11",
|
.conn_id = "11",
|
||||||
.conn_mode = MGCP_CONN_RECV_SEND,
|
.conn_mode = MGCP_CONN_RECV_SEND,
|
||||||
.ptime = 20,
|
.ptime = 20,
|
||||||
.ptmap = {
|
.codecs[0] = CODEC_GSM_8000_1,
|
||||||
{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
|
.codecs[1] = CODEC_AMR_8000_1,
|
||||||
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
|
.codecs[2] = CODEC_GSMEFR_8000_1,
|
||||||
{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
|
.codecs_len = 1,
|
||||||
},
|
.ptmap[0].codec = CODEC_GSMEFR_8000_1,
|
||||||
|
.ptmap[0].pt = 96,
|
||||||
.ptmap_len = 1,
|
.ptmap_len = 1,
|
||||||
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
|
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
|
||||||
.x_osmo_osmux_cid = -1, /* wildcard */
|
.x_osmo_osmux_cid = -1, /* wildcard */
|
||||||
@@ -175,9 +179,9 @@ void test_mgcp_msg(void)
|
|||||||
mgcp_msg.presence =
|
mgcp_msg.presence =
|
||||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
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);
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||||
mgcp_msg.ptmap_len = 1;
|
mgcp_msg.codecs_len = 1;
|
||||||
printf("%s\n", (char *)msg->data);
|
printf("%s\n", (char *)msg->data);
|
||||||
|
|
||||||
printf("Generated CRCX message (three codecs, one with custom pt):\n");
|
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 =
|
||||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
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);
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||||
mgcp_msg.ptmap_len = 1;
|
mgcp_msg.codecs_len = 1;
|
||||||
printf("%s\n", (char *)msg->data);
|
printf("%s\n", (char *)msg->data);
|
||||||
|
|
||||||
printf("Generated MDCX message:\n");
|
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_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
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);
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||||
mgcp_msg.ptmap_len = 1;
|
mgcp_msg.codecs_len = 1;
|
||||||
printf("%s\n", (char *)msg->data);
|
printf("%s\n", (char *)msg->data);
|
||||||
|
|
||||||
printf("Generated MDCX message (three codecs, one with custom pt):\n");
|
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_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
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);
|
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||||
mgcp_msg.ptmap_len = 1;
|
mgcp_msg.codecs_len = 1;
|
||||||
printf("%s\n", (char *)msg->data);
|
printf("%s\n", (char *)msg->data);
|
||||||
|
|
||||||
printf("Generated DLCX message:\n");
|
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
|
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
|
||||||
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
|
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
|
||||||
.ptime = 20,
|
.ptime = 20,
|
||||||
.ptmap = {
|
.codecs[0] = CODEC_AMR_8000_1,
|
||||||
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
|
.codecs_len = 1
|
||||||
},
|
|
||||||
.ptmap_len = 1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("\n%s():\n", __func__);
|
printf("\n%s():\n", __func__);
|
||||||
@@ -529,7 +531,7 @@ void test_sdp_section_start(void)
|
|||||||
OSMO_ASSERT(!failures);
|
OSMO_ASSERT(!failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_map_str_to_codec(void)
|
static void test_map_pt_to_codec(void)
|
||||||
{
|
{
|
||||||
/* Full form */
|
/* Full form */
|
||||||
OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
|
OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
|
||||||
@@ -673,214 +675,6 @@ void test_mgcp_client_e1_epname(void)
|
|||||||
OSMO_ASSERT(epname == NULL);
|
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[] = {
|
static const struct log_info_cat log_categories[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -909,11 +703,9 @@ int main(int argc, char **argv)
|
|||||||
test_mgcp_client_cancel();
|
test_mgcp_client_cancel();
|
||||||
test_sdp_section_start();
|
test_sdp_section_start();
|
||||||
test_map_codec_to_pt_and_map_pt_to_codec();
|
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_mgcp_client_e1_epname();
|
||||||
|
|
||||||
test_parse_response();
|
|
||||||
|
|
||||||
printf("Done\n");
|
printf("Done\n");
|
||||||
fprintf(stderr, "Done\n");
|
fprintf(stderr, "Done\n");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
@@ -137,51 +137,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-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-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!
|
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
|
Done
|
||||||
|
|||||||
Reference in New Issue
Block a user