Compare commits
224 Commits
Author | SHA1 | Date |
---|---|---|
Oliver Smith | fa393fa1e9 | |
Oliver Smith | e0fc37a437 | |
Oliver Smith | 4aa2b0e35b | |
Pau Espin | e01f6e7f33 | |
Pau Espin | 388b48d14e | |
Harald Welte | 352b967d1b | |
Harald Welte | ed4da25f2f | |
Harald Welte | 5abda312ed | |
Harald Welte | 75862d3131 | |
Harald Welte | 8733542b13 | |
Harald Welte | d7aac20cc1 | |
Harald Welte | 8b5361412c | |
Harald Welte | 3a971ba0d1 | |
Neels Hofmeyr | c4b90354ca | |
Harald Welte | 28fd236044 | |
Neels Hofmeyr | 17b5701f19 | |
Neels Hofmeyr | 9bea6eb78c | |
Neels Hofmeyr | fd57bd5f6f | |
Neels Hofmeyr | d0dbda4106 | |
Neels Hofmeyr | 35a738214c | |
Neels Hofmeyr | afbe872045 | |
Harald Welte | 909be19285 | |
Vadim Yanitskiy | 8ee08c6b78 | |
Neels Hofmeyr | c053e07336 | |
Neels Hofmeyr | 2b30cbdfa8 | |
Neels Hofmeyr | c9df010416 | |
Neels Hofmeyr | 3a3e1b57c6 | |
Neels Hofmeyr | 186d4f1a0b | |
Neels Hofmeyr | cc2f7937ed | |
Neels Hofmeyr | 960c031a67 | |
Neels Hofmeyr | 4993452561 | |
Neels Hofmeyr | 43eed63b09 | |
Vadim Yanitskiy | 7a6d9c2f72 | |
Vadim Yanitskiy | f3715dc0d3 | |
Vadim Yanitskiy | a68a863b9d | |
Neels Hofmeyr | 18717f5247 | |
Neels Hofmeyr | 677b5396cb | |
Neels Hofmeyr | 5d0e07112f | |
Pau Espin | a5acaa68db | |
Pau Espin | 7787a3aeae | |
Neels Hofmeyr | dd1ddf74fc | |
Neels Hofmeyr | 5e101c9fed | |
Pau Espin | f6db465082 | |
Pau Espin | a7e6fbc220 | |
Neels Hofmeyr | cd132126ef | |
Andreas Eversberg | 249d21eb1e | |
Neels Hofmeyr | 0127a0608d | |
Neels Hofmeyr | 8b663e4d7c | |
Keith Whyte | 5e5c7bc176 | |
Neels Hofmeyr | c695e9f972 | |
Oliver Smith | 2bdad960ff | |
Pau Espin | 58d5b97831 | |
Pau Espin | 6225b5cecb | |
Pau Espin | c415ed5113 | |
Pau Espin | 730a1f28d2 | |
Andreas Eversberg | af67178581 | |
Andreas Eversberg | dc7dfd0bbd | |
Neels Hofmeyr | c364f4ab5a | |
Neels Hofmeyr | e9989b9e76 | |
Oliver Smith | 9423817311 | |
Oliver Smith | 292ba1bdb1 | |
Pau Espin | 10d9f8dcf4 | |
Pau Espin | 4c0658955e | |
Pau Espin | e9164c295d | |
Pau Espin | 563386e8bb | |
Pau Espin | af0f58fac7 | |
Pau Espin | 2e411f33a0 | |
Pau Espin | 8e8d59ff0e | |
Philipp Maier | 14da3a33cb | |
Pau Espin | ea2035326d | |
Philipp Maier | 2bfa708527 | |
Oliver Smith | 72f911513e | |
Philipp Maier | 3d0676a791 | |
Philipp Maier | 4c4d227624 | |
Philipp Maier | 0e8310fa6c | |
Vadim Yanitskiy | e3624562dc | |
Oliver Smith | d5057ec7b8 | |
Philipp Maier | 72761b312b | |
Oliver Smith | a312523be4 | |
Neels Hofmeyr | 45fe47cea7 | |
Neels Hofmeyr | ce356eec1f | |
Philipp Maier | cca1d180f5 | |
Oliver Smith | 833ab4b083 | |
Vadim Yanitskiy | d358ca14a9 | |
Philipp Maier | 3699ef06a4 | |
Philipp Maier | 9dd80ca1f8 | |
Philipp Maier | 621e8666ff | |
Philipp Maier | ec967d74f7 | |
Philipp Maier | 3ccf02a300 | |
Philipp Maier | b6795ddfd2 | |
Pau Espin | 747fbce4ce | |
Vadim Yanitskiy | e1da8c9d2c | |
Vadim Yanitskiy | e78221d273 | |
Pau Espin | 6c303664f5 | |
Philipp Maier | 544016d8e6 | |
Philipp Maier | 263a1a3e8f | |
Philipp Maier | 30bdf94102 | |
Oliver Smith | 0dbaaadc06 | |
arehbein | 671c37b72b | |
Philipp Maier | 2a9ba66922 | |
Philipp Maier | f8abd0ec0c | |
Harald Welte | 1a7048d69a | |
Philipp Maier | c70c08cd49 | |
Philipp Maier | a8f13286ff | |
Philipp Maier | b9e7569217 | |
Philipp Maier | 057decfe3a | |
Pau Espin | 342a9a9418 | |
Harald Welte | 22f9cf2687 | |
Oliver Smith | 26d6b2b5ce | |
Oliver Smith | 169d50ed4a | |
Philipp Maier | 82dfb505db | |
Max | 9c0d105d09 | |
Pau Espin | ded02cfc29 | |
Pau Espin | 0cbed362cd | |
Pau Espin | 310e41cdf3 | |
Max | a55bfdc436 | |
Harald Welte | 6ea8d7dac6 | |
Harald Welte | 9befdeb673 | |
Neels Hofmeyr | 5fb814b6b9 | |
Pau Espin | 9ac9cb963d | |
Pau Espin | 377d39122d | |
Pau Espin | d1e94c7ac3 | |
Pau Espin | 6db3f7f1cb | |
Pau Espin | 58c0b0a6f7 | |
Pau Espin | cca55247ed | |
Pau Espin | d266c374ee | |
Pau Espin | d358d71206 | |
Neels Hofmeyr | 5e6661eece | |
Neels Hofmeyr | c1468ef7a5 | |
Neels Hofmeyr | 24763eaa73 | |
Neels Hofmeyr | d8c2f31a87 | |
Pau Espin | 01b812ea76 | |
Pau Espin | 0807771b9e | |
Pau Espin | 103e50a561 | |
Pau Espin | 3a914e33e9 | |
Pau Espin | 2172f402a5 | |
Pau Espin | 8c138fe89c | |
Pau Espin | 7881f7da0b | |
Pau Espin | d17a9de79e | |
Pau Espin | 8e74c63e15 | |
Pau Espin | 80dd576ad2 | |
Oliver Smith | cb922b646f | |
Pau Espin | 5d8b5b0935 | |
Pau Espin | 35bd2523e2 | |
Pau Espin | f45a9b9760 | |
Pau Espin | f48cd95bbc | |
Pau Espin | 7558c20973 | |
Pau Espin | 6ddc79b6ed | |
Pau Espin | ff5921573a | |
Pau Espin | d4ad77d326 | |
Pau Espin | a6917fecb1 | |
Pau Espin | 58877f04e3 | |
Pau Espin | d4707e2185 | |
Pau Espin | f633302c73 | |
Pau Espin | 36413c011f | |
Pau Espin | 833281dcb9 | |
Pau Espin | 07bbd766c5 | |
Pau Espin | c7c8e649f1 | |
Pau Espin | c0e1b1aec5 | |
Pau Espin | 9735d21b9d | |
Pau Espin | 705565d745 | |
Pau Espin | 63088e0e61 | |
Pau Espin | 887c93e198 | |
Pau Espin | 2ca48823b1 | |
Pau Espin | e7de137b29 | |
Pau Espin | c1ad7fd92b | |
Pau Espin | 3779919551 | |
Pau Espin | 8e0d101997 | |
Pau Espin | 654b68d602 | |
Pau Espin | 70c03f5e44 | |
Pau Espin | e56ec4a146 | |
Pau Espin | 5ffd127384 | |
Pau Espin | 051eb4d563 | |
Pau Espin | e740665cab | |
Pau Espin | abb9d47c90 | |
Pau Espin | 2dd2b33030 | |
Pau Espin | 69f15e4e95 | |
Pau Espin | b0ea7976bf | |
Pau Espin | 9d939b6d5d | |
Pau Espin | de805b6772 | |
Pau Espin | cb25a0aa48 | |
Pau Espin | 72eff2cf6a | |
Pau Espin | 1c5fcb0791 | |
Pau Espin | 48fb176fbc | |
Pau Espin | 4d090d85f4 | |
Pau Espin | 81c5847434 | |
Pau Espin | d48a811f6c | |
Pau Espin | b7f52b414e | |
Pau Espin | ea7aaf2eca | |
Pau Espin | 432ee9d150 | |
Pau Espin | b4a59475d2 | |
Pau Espin | 2177919edb | |
Pau Espin | 87f114a1d0 | |
Pau Espin | 928a20b540 | |
Pau Espin | b9022497d8 | |
Pau Espin | 582c2bf7b0 | |
Pau Espin | 663ba5c41f | |
Pau Espin | daf5bcea99 | |
Pau Espin | a29f155301 | |
Pau Espin | 941e317c97 | |
Pau Espin | 3fbf035923 | |
Pau Espin | 21bcf6abd8 | |
Pau Espin | 26e810d8a9 | |
Pau Espin | 4d1a52d463 | |
Pau Espin | 83df47cd7a | |
Pau Espin | c5bbb78ffe | |
Harald Welte | e0e5a772f4 | |
Pau Espin | e39ae87ea3 | |
Pau Espin | 8b0a614e43 | |
Pau Espin | c61664c2b2 | |
Pau Espin | 15e7e4f37d | |
Pau Espin | ab8371c6d7 | |
Pau Espin | 8c777990a5 | |
Pau Espin | ec5e85b84e | |
Pau Espin | ab4e8663e1 | |
Pau Espin | a4f783b51b | |
Pau Espin | 479cf76e55 | |
Pau Espin | 33639166a2 | |
Max | 709aad28ed | |
Pau Espin | 5892b2e4db | |
Pau Espin | f1f73b8e1d | |
Philipp Maier | 0fdc08c551 | |
Vadim Yanitskiy | 5be57da075 | |
Pau Espin | 147184eb06 |
|
@ -24,7 +24,7 @@ pkgconfig_DATA = \
|
|||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-mgw.spec.in \
|
||||
README.md \
|
||||
debian \
|
||||
git-version-gen \
|
||||
osmoappdesc.py \
|
||||
|
|
24
README
24
README
|
@ -1,24 +0,0 @@
|
|||
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
|
|
@ -0,0 +1,102 @@
|
|||
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.
|
17
TODO-RELEASE
17
TODO-RELEASE
|
@ -24,3 +24,20 @@
|
|||
# If any interfaces have been removed or changed since the last public release, a=0.
|
||||
#
|
||||
#library what description / commit summary line
|
||||
libosmo-mgcp-client remove public API These public API items have not been called by any of our osmo-programs
|
||||
for many years. Any sane caller of libosmo-mgcp-client should use the
|
||||
higher level osmo_mgcpc_* API instead. Move these to a private header:
|
||||
struct mgcp_response_head
|
||||
struct mgcp_response
|
||||
struct mgcp_msg
|
||||
mgcp_response_parse_params()
|
||||
mgcp_client_tx()
|
||||
mgcp_client_cancel()
|
||||
mgcp_msg_gen()
|
||||
mgcp_msg_trans_id()
|
||||
libosmo-mgcp-client deprecate public API New code should no longer use codecs[], instead use ptmap[].codec. There
|
||||
is backwards compat code that moves codecs[] entries, if any, over to
|
||||
ptmap[], so callers may migrate at own leisure.
|
||||
osmo-mgw remove cfg Remove VTY config item 'sdp audio fmtp-extra' (see OS#6313)
|
||||
libosmocore bump_dep; workaround Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
|
||||
has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
|
||||
|
|
19
configure.ac
19
configure.ac
|
@ -44,15 +44,16 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
|
|||
AC_SUBST(LIBRARY_DLSYM)
|
||||
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.5.0)
|
||||
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
||||
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
|
||||
AC_ARG_ENABLE(sanitize,
|
||||
|
@ -79,6 +80,7 @@ AC_ARG_ENABLE(werror,
|
|||
if test x"$werror" = x"yes"
|
||||
then
|
||||
WERROR_FLAGS="-Werror"
|
||||
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
|
||||
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
||||
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
||||
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
||||
|
@ -202,5 +204,4 @@ AC_OUTPUT(
|
|||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/osmo-mgw.spec
|
||||
Makefile)
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
#
|
||||
# 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.2.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmocoding) >= 1.7.0
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.3.0
|
||||
BuildRequires: pkgconfig(libosmotrau) >= 1.3.0
|
||||
%{?systemd_requires}
|
||||
|
||||
%description
|
||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
|
||||
|
||||
%package -n libosmo-mgcp-client9
|
||||
Summary: Osmocom's Media Gateway Control Protocol client library
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-mgcp-client9
|
||||
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-client9 = %{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-client9 -p /sbin/ldconfig
|
||||
%postun -n libosmo-mgcp-client9 -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-client9
|
||||
%{_libdir}/libosmo-mgcp-client.so.9*
|
||||
|
||||
%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
|
|
@ -1,11 +1,24 @@
|
|||
[Unit]
|
||||
Description=Osmocom Media Gateway (MGW)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
LimitNOFILE=65536
|
||||
StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
|
||||
RestartSec=2
|
||||
AmbientCapabilities=CAP_SYS_NICE
|
||||
# CPU scheduling policy:
|
||||
CPUSchedulingPolicy=rr
|
||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
|
||||
CPUSchedulingPriority=1
|
||||
# See sched(7) for further details on real-time policies and priorities
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -1,3 +1,218 @@
|
|||
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
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mgcp-client: Remove impossible code path
|
||||
* mgcp_osmux: Drop duplicated conn_osmux_release_cid() in code path
|
||||
* Use Osmux default port define from libosmo-netif
|
||||
* osmux: Use new osmux APIs to let libosmo-netif alloc struct osmux_out_handle
|
||||
* mgw: Fix osmux conn local IP selection
|
||||
* cosmetic: osmux: Fix wrong indentation
|
||||
* mgw: Use X-Osmux string define
|
||||
* Add Osmux log category
|
||||
* cosmetic: main: Properly format log_info_cat
|
||||
* osmux: Use better name for function which may allocate a new struct
|
||||
* osmux: Use osmo_sockaddr wherever possible
|
||||
* osmux: Log refcounting of osmux_handle_list
|
||||
* osmux: Fix memleak on error code path
|
||||
* osmux: don't store conn ptr inside shared osmux_handle
|
||||
* osmux: set log level of expected code path to INFO
|
||||
* cosmetic: vty: Fix indentation whitespace
|
||||
* osmux: Log sendto() error
|
||||
* cosmetic: mgcp_conn.h: fix indentation whitespace
|
||||
* osmux: Attach osmux to virtual trunk
|
||||
* osmux: Clean up helper macro osmux_chunk_length()
|
||||
* osmux: Get rid of static NULL talloc context
|
||||
* Fix typo in ratectr description
|
||||
* mgcp_conn: rename field s/rate_ctr_group/ctrg/g
|
||||
* Use 'static const' instead of 'const static' everywhere
|
||||
* osmux: Add connection and global rate counters
|
||||
* cosmetic: osmux: Fix formatting of if-else brackets
|
||||
* osmux: Rename field osmux usage policy and define it with proper type
|
||||
* Use bool type instead of int in config field
|
||||
* osmux: Support local CID != remote CID
|
||||
* osmux: Fix incorrect rate_ctr_group used in mgcp_osmux.c
|
||||
* osmux: Improve per-conn tx rate counters
|
||||
* vty: show per-connection Osmux VTY stats
|
||||
* osmux: Rename field s/init/initialized
|
||||
* osmux: Allocate rate counters during initialization of osmux conn
|
||||
* cosmetic: osmux: Drop extra empty line
|
||||
* osmux: Drop unneeded comment block
|
||||
* osmux: Lower log level when osmux batch received for unknown CID
|
||||
* osmux: Keep decoding osmux pkt if a batch contains an unknown CID
|
||||
* Allocate struct osmux_in_handle through new libosmo-netif APIs
|
||||
* osmux: Drop logging of osmux internal counters
|
||||
* osmux: cleanup misleading code calling rtp_bridge_cb
|
||||
* osmux: Unify rtp_conn osmux type into a single type
|
||||
* osmux: Match remote address in osmux_conn_lookup()
|
||||
* osmux: Fill in from_addr in struct osmo_rtp_msg_ctx
|
||||
* osmux: Log remote address upon rx of osmux pkt
|
||||
* send_dummy: Use proper condition to test if conn is osmux
|
||||
* Fix regression in detection of legacy dummy packets
|
||||
* Use new libosmocore API osmo_sockaddr_is_any()
|
||||
* Get rid of separate rtp_port field
|
||||
* osmux: Use available API to check if remote end is known
|
||||
* Add Osmux IPv6 support
|
||||
* Clean up local var pointers in mgcp_get_local_addr()
|
||||
* osmux: Change couple log lines to OSMUX category
|
||||
* osmux: Add square brackets around IPv6 address to distinguish port in log line
|
||||
* osmux: Drop unused role parameter
|
||||
* osmux: cosmetic: Fix indentation
|
||||
* Check once if remote addr is available when sending dummy packet
|
||||
* osmux: Simplify and constify param passing
|
||||
* osmux: Set conn->type during osmux_init_conn()
|
||||
* osmux: Make conn_osmux_{allocate,release}_local_cid() APIs static
|
||||
* osmux: Define osmux_dummy cfg as boolean
|
||||
* osmux: Move setting OSMUX_STATE_DISABLED to initializer function
|
||||
* osmux: Erase references to bsc-nat
|
||||
* mgcp_conn_dump(): Separate dump for osmux and iuup connections
|
||||
* osmux: Introduce osmux peer-behind-nat (on|off) and rework conn activation
|
||||
* osmux: Clean up mgcp_config osmux fields
|
||||
* cosmetic: Fix typo in comment
|
||||
* mgcp-client: pool: Improve documentation of some internal fields
|
||||
* mgcp-client: Avoid double iteration picking client from pool
|
||||
* mgcp-client: Fix typo in internal function name
|
||||
* mgcp-client: Rename internal field in mgcp_client_pool
|
||||
* mgcp-client: Move & rename helper function outside of vty code
|
||||
* mgcp-client: Create alloc() and free() internal APIs for mgcp_client_pool_member
|
||||
* mgcp-client: Move internal API acting on mgcp_client_pool to the correct file section
|
||||
* mgcp-client: Refactor reinit of mgcp clients
|
||||
* mgcp-client: Rearrange order of structs and APIs in header
|
||||
* mgcp-client: Rearrange internal backpointers
|
||||
* mgcp-client: Introduce APIs to manually select mgcp_client from pool
|
||||
* mgcp-client: vty: Write deprecation warning using non-mgw nodes
|
||||
* mgcp-client: Use random free local port by default
|
||||
* mgcp-client: Convert users supporting new MGW Pool VTY node during write-config
|
||||
* mgcp-client: Introduce API mgcp_client_pool_config_write
|
||||
* mgcp-client: Add new VTY commands under mgw node without mgw prefix
|
||||
* mgcp-client: Fix 'mgw endpoint-range' command dropped from old VTY node
|
||||
* mgcp-client: Refactor system keeping old users not calling mgcp_client_pool_config_write() working
|
||||
* mgcp-client: Fix no 'mgw ' prefix written in old VTY node
|
||||
* Fix misleading error log
|
||||
* mgcp_send: Use mgcp_conn_rtp_is_iuup() helper
|
||||
* cosmetic: Clarify and fix typos in comment
|
||||
* mgw: Log unexpected RTP AMR OA-vs-BE payload
|
||||
* Rename and move func checking if amr mode is explicitly configured
|
||||
* mgw: rx_rtp(): reorder checks and handlings
|
||||
* mgw: Rename s/mgcp_send_rtp/mgcp_conn_rtp_dispatch_rtp/
|
||||
* osmux: Rename function and pass msgb directly to it
|
||||
* osmux: Make sure RTP AMR feed to osmux is in octet-aligned mode
|
||||
* Improve logging on AMR OA<->BWE conversion failure
|
||||
* osmux: Rotate over available Osmux CID when allocating a new one
|
||||
* osmux: Use new osmux_xfrm_input API to set name on each link
|
||||
* iuup: Use osmo_amr_ft_valid() API
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* libosmo-mgcp-client: add -no-undefined to *_la_LDFLAGS
|
||||
|
||||
[ Philipp Maier ]
|
||||
* mgcp_e1: fix apidoc
|
||||
* mgcp_network: improve coment
|
||||
|
||||
[ Max ]
|
||||
* Set working directory in systemd service file
|
||||
* Add realtime scheduling and set priority in service file
|
||||
* ctrl: take both address and port from vty config
|
||||
|
||||
[ Harald Welte ]
|
||||
* Make osmo_mgcpc_ep_fsm_pre_term() static
|
||||
* Support building with -Werror=strict-prototypes / -Werror=old-style-definition
|
||||
* Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
|
||||
* update outdated vty copyright statement
|
||||
|
||||
[ Oliver Smith ]
|
||||
* mgcp_client_pool.h: add missing stdbool include
|
||||
* Fix various typos
|
||||
* mgcp_client: add new clearmode codec
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* AMR->IuUP: do not crash on AMR data before IuUP Init
|
||||
* AMR->IuUP: properly translate Q -> FQC
|
||||
* IuUP->AMR: do not patch payload type a second time
|
||||
* IuUP->AMR: log whether converting to AMR OA or BE
|
||||
* AMR->IuUP: log conversion, like for the flipside
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 16:58:41 +0100
|
||||
|
||||
osmo-mgw (1.10.0) unstable; urgency=medium
|
||||
|
||||
[ Eric ]
|
||||
|
|
|
@ -1 +1 @@
|
|||
9
|
||||
10
|
||||
|
|
|
@ -2,14 +2,14 @@ Source: osmo-mgw
|
|||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Build-Depends: debhelper (>=9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
dh-autoreconf,
|
||||
pkg-config,
|
||||
autotools-dev,
|
||||
libosmocore-dev (>= 1.7.0),
|
||||
libosmo-netif-dev (>= 1.2.0),
|
||||
libosmo-abis-dev (>= 1.3.0),
|
||||
osmo-gsm-manuals-dev (>= 1.3.0)
|
||||
libosmocore-dev (>= 1.9.0),
|
||||
libosmo-netif-dev (>= 1.4.0),
|
||||
libosmo-abis-dev (>= 1.5.0),
|
||||
osmo-gsm-manuals-dev (>= 1.5.0)
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
|
||||
|
@ -21,7 +21,7 @@ Multi-Arch: foreign
|
|||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
||||
|
||||
Package: libosmo-mgcp-client9
|
||||
Package: libosmo-mgcp-client12
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
|
@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
|
|||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: libosmo-mgcp-client9 (= ${binary:Version}), ${misc:Depends}
|
||||
Depends: libosmo-mgcp-client12 (= ${binary:Version}), ${misc:Depends}
|
||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
|
||||
|
||||
Package: osmo-mgw-doc
|
||||
|
|
|
@ -6,7 +6,7 @@ Files: *
|
|||
Copyright: 2009-2014 On-Waves
|
||||
2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
|
||||
2016-2017 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
2016-2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
License: AGPL-3.0+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
|
@ -22,7 +22,7 @@ License: AGPL-3.0+
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Files: src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
|
||||
Copyright: 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
Copyright: 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
|
||||
2009 by Harald Welte <laforge@gnumonks.org>
|
||||
2009-2011 by Holger Hans Peter Freyther
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#!/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,20 +1,25 @@
|
|||
!
|
||||
! MGCP configuration example
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
|
||||
e1_input
|
||||
e1_line 0 driver dahdi
|
||||
e1_line 0 port 0
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp port-range 4002 16001
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 512
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
rtp-patch ssrc
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
!
|
||||
! MGCP configuration example
|
||||
!
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp port-range 4002 16001
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 512
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
rtp-patch ssrc
|
||||
|
|
|
@ -91,4 +91,10 @@ encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
|
|||
not yet useable.
|
||||
|
||||
NOTE: the VTY command "show mgcp" can be used to get a list of all available
|
||||
endpoints (including identifiers)
|
||||
endpoints (including identifiers)
|
||||
|
||||
=== The `null` endpoint
|
||||
|
||||
OsmoMGW offers a special `null@<domain>` endpoint which can be audited at all times.
|
||||
This is useful for MGCP clients who wish to submit requests to OsmoMGW
|
||||
periodically to find out whether it is still reachable and in a working state.
|
|
@ -23,3 +23,20 @@ arguments:
|
|||
Disable colors for logging to stderr. This has mostly been
|
||||
deprecated by VTY based logging configuration, see <<logging>>
|
||||
for more information.
|
||||
|
||||
|
||||
=== Configure limits
|
||||
|
||||
When servicing hundreds of media endpoints, it may be necessary to adjust the
|
||||
operating system's limit on open file descriptors for the osmo-mgw process. A
|
||||
typical default limit imposed by operating systems is 1024; this would be
|
||||
exceeded by, for example, about 256 active voice calls with 4 RTP/RTPC ports
|
||||
each, sockets for other interfaces not considered yet.
|
||||
|
||||
It should be ok to set an OS limit on open file descriptors as high as 65536
|
||||
for osmo-mgw, which practically rules out failure from running out of file
|
||||
descriptors anywhere (<16,000 active calls).
|
||||
|
||||
When using systemd, the file descriptor limit may be adjusted in the service
|
||||
file by the `LimitNOFILE` setting ("Number of Open FILE descriptors"). OsmoMGW
|
||||
ships a systemd service file with a high LimitNOFILE setting.
|
||||
|
|
|
@ -3,10 +3,14 @@ SUBDIRS = \
|
|||
$(NULL)
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
osmocom/mgcp_client/defs.h \
|
||||
osmocom/mgcp_client/mgcp_client.h \
|
||||
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_client_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_client_pool.h \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
osmocom/mgcp/mgcp.h \
|
||||
osmocom/mgcp/mgcp_common.h \
|
||||
osmocom/mgcp/osmux.h \
|
||||
|
|
|
@ -6,7 +6,6 @@ noinst_HEADERS = \
|
|||
mgcp_endp.h \
|
||||
mgcp_sdp.h \
|
||||
mgcp_codec.h \
|
||||
mgcp_ctrl.h \
|
||||
mgcp_trunk.h \
|
||||
debug.h \
|
||||
mgcp_ratectr.h \
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
enum {
|
||||
DRTP,
|
||||
DE1,
|
||||
DOSMUX,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/osmo_io.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp_common.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -69,12 +71,10 @@ typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
|||
/**
|
||||
* Return:
|
||||
* < 0 in case no audio was processed
|
||||
* >= 0 in case audio was processed. The remaining payload
|
||||
* length will be returned.
|
||||
* >= 0 in case audio was processed.
|
||||
*/
|
||||
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
struct mgcp_rtp_end *dst_end, struct msgb *msg);
|
||||
|
||||
struct mgcp_conn_rtp;
|
||||
|
||||
|
@ -137,8 +137,6 @@ struct mgcp_config {
|
|||
mgcp_processing rtp_processing_cb;
|
||||
mgcp_processing_setup setup_rtp_processing_cb;
|
||||
|
||||
mgcp_get_format get_net_downlink_format_cb;
|
||||
|
||||
struct osmo_wqueue gw_fd;
|
||||
|
||||
struct mgcp_port_range net_ports;
|
||||
|
@ -156,24 +154,26 @@ struct mgcp_config {
|
|||
|
||||
enum mgcp_role role;
|
||||
|
||||
/* osmux translator: 0 means disabled, 1 means enabled */
|
||||
int osmux;
|
||||
/* addr to bind the server to */
|
||||
char osmux_addr[INET6_ADDRSTRLEN];
|
||||
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
|
||||
* the osmux socket is already initialized.
|
||||
*/
|
||||
int osmux_init;
|
||||
/* osmux batch factor: from 1 to 4 maximum */
|
||||
int osmux_batch;
|
||||
/* osmux batch size (in bytes) */
|
||||
int osmux_batch_size;
|
||||
/* osmux port */
|
||||
uint16_t osmux_port;
|
||||
/* Pad circuit with dummy messages until we see the first voice
|
||||
* message.
|
||||
*/
|
||||
uint16_t osmux_dummy;
|
||||
struct {
|
||||
/* Osmux usage policy: */
|
||||
enum osmux_usage usage;
|
||||
/* addr to bind the server to */
|
||||
char *local_addr_v4;
|
||||
char *local_addr_v6;
|
||||
/* osmux port */
|
||||
uint16_t local_port;
|
||||
/* The osmux socket is allocated on demand (1st time used).
|
||||
* This tells us if the osmux socket is already initialized. */
|
||||
bool initialized;
|
||||
/* osmux batch factor: from 1 to 4 maximum */
|
||||
int batch_factor;
|
||||
/* osmux batch size (in bytes) */
|
||||
int batch_size;
|
||||
/* Pad circuit with dummy AMR frames if no payload to transmit is available */
|
||||
bool dummy_padding;
|
||||
/* Whether peer is behind NAT (Retrieve remote addr from 1st received Osmux packet) */
|
||||
bool peer_behind_nat;
|
||||
} osmux;
|
||||
/* domain name of the media gateway */
|
||||
char domain[255+1];
|
||||
|
||||
|
@ -205,6 +205,5 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
|
|||
int mgcp_send_reset_all(struct mgcp_config *cfg);
|
||||
|
||||
|
||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
|
||||
uint8_t prio);
|
||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
|
||||
int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio);
|
||||
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len);
|
||||
|
|
|
@ -13,8 +13,9 @@ struct mgcp_conn_rtp;
|
|||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
|
||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
|
||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
|
||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
|
||||
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_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);
|
||||
|
|
|
@ -47,6 +47,7 @@ enum mgcp_connection_mode {
|
|||
MGCP_CONN_SEND_ONLY = 2,
|
||||
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
|
||||
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
|
||||
MGCP_CONN_CONFECHO = 8 | MGCP_CONN_RECV_SEND,
|
||||
};
|
||||
|
||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
|
||||
|
@ -67,11 +68,11 @@ struct mgcp_codec_param {
|
|||
/* Ensure that the msg->l2h is NUL terminated. */
|
||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
{
|
||||
unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
|
||||
unsigned char *tail = msg->tail; /* char after l2 data */
|
||||
if (tail[-1] == '\0')
|
||||
/* nothing to do */;
|
||||
else if (msgb_tailroom(msg) > 0)
|
||||
tail[0] = '\0';
|
||||
msgb_put_u8(msg, (uint8_t)'\0');
|
||||
else if (tail[-1] == '\r' || tail[-1] == '\n')
|
||||
tail[-1] = '\0';
|
||||
else {
|
||||
|
|
|
@ -46,10 +46,14 @@ LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
|
|||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
|
||||
enum mgcp_conn_rtp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
MGCP_RTP_OSMUX,
|
||||
MGCP_RTP_IUUP,
|
||||
};
|
||||
extern const struct value_string mgcp_conn_rtp_type_names[];
|
||||
static inline const char *mgcp_conn_rtp_type_name(enum mgcp_conn_rtp_type val)
|
||||
{
|
||||
return get_value_string(mgcp_conn_rtp_type_names, val);
|
||||
}
|
||||
|
||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||
* contains a useful connection description (currently only RTP) */
|
||||
|
@ -80,19 +84,20 @@ struct mgcp_conn_rtp {
|
|||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Is cid holding valid data? is it allocated from pool? */
|
||||
bool cid_allocated;
|
||||
/* Allocated Osmux circuit ID for this conn */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
/* Is local_cid holding valid data? is it allocated from pool? */
|
||||
bool local_cid_allocated;
|
||||
/* Allocated local Osmux circuit ID for this conn */
|
||||
uint8_t local_cid;
|
||||
/* Is remote_cid holding valid data? was it already received from client? */
|
||||
bool remote_cid_present;
|
||||
/* Received remote Osmux circuit ID for this conn */
|
||||
uint8_t remote_cid;
|
||||
/* handle to batch messages, shared (refcounted) among several conns */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
/* handle to unbatch messages, one allocated and owned per conn */
|
||||
struct osmux_out_handle *out;
|
||||
/* statistics: */
|
||||
struct rate_ctr_group *ctrg;
|
||||
} osmux;
|
||||
|
||||
struct {
|
||||
|
@ -103,7 +108,7 @@ struct mgcp_conn_rtp {
|
|||
struct osmo_iuup_rnl_prim *init_ind;
|
||||
} iuup;
|
||||
|
||||
struct rate_ctr_group *rate_ctr_group;
|
||||
struct rate_ctr_group *ctrg;
|
||||
};
|
||||
|
||||
/*! MGCP connection (untyped) */
|
||||
|
@ -145,12 +150,12 @@ struct mgcp_conn {
|
|||
enum {
|
||||
IN_STREAM_ERR_TSTMP_CTR,
|
||||
OUT_STREAM_ERR_TSTMP_CTR,
|
||||
RTP_PACKETS_RX_CTR,
|
||||
RTP_OCTETS_RX_CTR,
|
||||
RTP_PACKETS_TX_CTR,
|
||||
RTP_OCTETS_TX_CTR,
|
||||
RTP_DROPPED_PACKETS_CTR,
|
||||
RTP_NUM_CONNECTIONS,
|
||||
RTP_PACKETS_RX_CTR,
|
||||
RTP_OCTETS_RX_CTR,
|
||||
RTP_PACKETS_TX_CTR,
|
||||
RTP_OCTETS_TX_CTR,
|
||||
RTP_DROPPED_PACKETS_CTR,
|
||||
RTP_NUM_CONNECTIONS,
|
||||
};
|
||||
|
||||
/* RTP per-connection statistics. Instances of the corresponding rate counter group
|
||||
|
@ -163,7 +168,7 @@ static const struct rate_ctr_desc mgcp_conn_rate_ctr_desc[] = {
|
|||
[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
|
||||
[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
|
||||
[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
|
||||
[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "dropped rtp packets."}
|
||||
[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "Dropped rtp packets."}
|
||||
};
|
||||
|
||||
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
|
||||
|
@ -181,9 +186,49 @@ static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
|
|||
[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
|
||||
};
|
||||
|
||||
/* Osmux connection related counters */
|
||||
enum {
|
||||
OSMUX_CHUNKS_RX_CTR,
|
||||
OSMUX_OCTETS_RX_CTR,
|
||||
OSMUX_RTP_PACKETS_TX_CTR,
|
||||
OSMUX_RTP_PACKETS_TX_DROPPED_CTR,
|
||||
OSMUX_AMR_OCTETS_TX_CTR,
|
||||
/* Only available in global stats: */
|
||||
OSMUX_NUM_CONNECTIONS,
|
||||
OSMUX_PACKETS_RX_CTR,
|
||||
OSMUX_PACKETS_TX_CTR,
|
||||
OSMUX_DROPPED_PACKETS_CTR,
|
||||
};
|
||||
|
||||
/* RTP per-connection statistics. Instances of the corresponding rate counter group
|
||||
* exist for the lifetime of an RTP connection.
|
||||
* Must be kept in sync with all_rtp_conn_rate_ctr_desc below */
|
||||
static const struct rate_ctr_desc mgcp_conn_osmux_rate_ctr_desc[] = {
|
||||
[OSMUX_CHUNKS_RX_CTR] = {"osmux:chunks_rx", "Inbound Osmux chunks."},
|
||||
[OSMUX_OCTETS_RX_CTR] = {"osmux:octets_rx", "Inbound Osmux octets."},
|
||||
[OSMUX_RTP_PACKETS_TX_CTR] = {"osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
|
||||
[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
|
||||
[OSMUX_AMR_OCTETS_TX_CTR] = {"osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
|
||||
};
|
||||
|
||||
/* Aggregated Osmux connection stats. These are updated when an Osmux connection is freed.
|
||||
* Must be kept in sync with mgcp_conn_osmux_rate_ctr_desc above */
|
||||
static const struct rate_ctr_desc all_osmux_conn_rate_ctr_desc[] = {
|
||||
[OSMUX_CHUNKS_RX_CTR] = {"all_osmux:chunks_rx", "Inbound Osmux chunks."},
|
||||
[OSMUX_OCTETS_RX_CTR] = {"all_osmux:octets_rx", "Inbound Osmux octets."},
|
||||
[OSMUX_RTP_PACKETS_TX_CTR] = {"all_osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
|
||||
[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"all_osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
|
||||
[OSMUX_AMR_OCTETS_TX_CTR] = {"all_osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
|
||||
/* These last counters below do not exist in per-connection stats, only here: */
|
||||
[OSMUX_NUM_CONNECTIONS] = {"all_osmux:num_closed_conns", "Total number of osmux connections closed."},
|
||||
[OSMUX_PACKETS_RX_CTR] = {"all_osmux:packets_rx", "Total inbound UDP/Osmux packets."},
|
||||
[OSMUX_PACKETS_TX_CTR] = {"all_osmux:packets_tx", "Total outbound UDP/Osmux packets."},
|
||||
[OSMUX_DROPPED_PACKETS_CTR] = {"all_osmux:dropped_packets", "Dropped outbound UDP/Osmux packets."}
|
||||
};
|
||||
|
||||
/* Was conn configured to handle Osmux? */
|
||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
|
||||
return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
|
||||
return conn->type == MGCP_RTP_OSMUX;
|
||||
}
|
||||
|
||||
/* Was conn configured to handle Osmux? */
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
|
||||
const char *bind_addr, uint16_t port);
|
||||
|
|
@ -23,5 +23,5 @@ static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6,
|
|||
|
||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
|
||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
|
||||
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);
|
||||
|
|
|
@ -40,8 +40,13 @@ LOGP(cat, level, "endpoint:%s " fmt, \
|
|||
endp ? endp->name : "none", \
|
||||
## args)
|
||||
|
||||
enum rtp_proto {
|
||||
MGCP_PROTO_RTP,
|
||||
MGCP_PROTO_RTCP,
|
||||
};
|
||||
|
||||
struct osmo_rtp_msg_ctx {
|
||||
int proto;
|
||||
enum rtp_proto proto;
|
||||
struct mgcp_conn_rtp *conn_src;
|
||||
struct osmo_sockaddr *from_addr;
|
||||
};
|
||||
|
@ -125,10 +130,10 @@ struct mgcp_endpoint {
|
|||
};
|
||||
|
||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
|
||||
bool mgcp_endp_is_wildcarded(const char *epname);
|
||||
bool mgcp_endp_is_null(const char *epname);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
||||
|
@ -140,3 +145,4 @@ void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
|||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/osmo_io.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
|
||||
/* The following constant defines an RTP dummy payload that is used for
|
||||
* "UDP Hole Punching" (NAT) */
|
||||
static const char rtp_dummy_payload[] = { 0x23 };
|
||||
#define MGCP_DUMMY_LOAD 0x23
|
||||
static const char rtp_dummy_payload[] = { MGCP_DUMMY_LOAD };
|
||||
|
||||
/* Check if the data in a given message buffer matches the rtp dummy payload
|
||||
* defined above */
|
||||
|
@ -92,7 +94,7 @@ struct mgcp_rtp_end {
|
|||
struct osmo_sockaddr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
int rtcp_port;
|
||||
|
||||
/* currently selected audio codec */
|
||||
struct mgcp_rtp_codec *codec;
|
||||
|
@ -107,7 +109,6 @@ struct mgcp_rtp_end {
|
|||
int frames_per_packet;
|
||||
uint32_t packet_duration_ms;
|
||||
int maximum_packet_time; /* -1: not set */
|
||||
char *fmtp_extra;
|
||||
/* are we transmitting packets (true) or dropping (false) outbound packets */
|
||||
bool output_enabled;
|
||||
/* FIXME: This parameter can be set + printed, but is nowhere used! */
|
||||
|
@ -120,8 +121,8 @@ struct mgcp_rtp_end {
|
|||
bool rfc5993_hr_convert;
|
||||
|
||||
/* Each end has a separate socket for RTP and RTCP */
|
||||
struct osmo_fd rtp;
|
||||
struct osmo_fd 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;
|
||||
|
@ -156,11 +157,10 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
|||
struct mgcp_rtp_state *state,
|
||||
struct mgcp_rtp_end *rtp_end,
|
||||
struct osmo_sockaddr *addr, struct msgb *msg);
|
||||
void 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_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
|
@ -178,5 +178,9 @@ void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_stat
|
|||
|
||||
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
|
||||
int id, int inc);
|
||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
|
||||
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
|
||||
int id);
|
||||
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
|
||||
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);
|
||||
|
|
|
@ -80,6 +80,8 @@ struct mgcp_ratectr_trunk {
|
|||
struct rate_ctr_group *mgcp_dlcx_ctr_group;
|
||||
/* Rate counter group which aggregates stats of individual RTP connections. */
|
||||
struct rate_ctr_group *all_rtp_conn_stats;
|
||||
/* Rate counter group which aggregates stats of individual Osmux connections. */
|
||||
struct rate_ctr_group *all_osmux_conn_stats;
|
||||
/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
|
||||
struct rate_ctr_group *e1_stats;
|
||||
};
|
||||
|
|
|
@ -27,12 +27,9 @@ struct mgcp_trunk {
|
|||
unsigned int trunk_nr;
|
||||
enum mgcp_trunk_type trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
|
@ -66,7 +63,7 @@ struct mgcp_trunk {
|
|||
/* E1 specific */
|
||||
struct {
|
||||
unsigned int vty_line_nr;
|
||||
bool ts_in_use[NUM_E1_TS-1];
|
||||
uint8_t ts_usecount[NUM_E1_TS-1];
|
||||
struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
|
||||
/* Note: on an E1 line TS 0 is devoted to framing and
|
||||
* alignment and therefore only NUM_E1_TS-1 timeslots
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
struct mgcp_conn_rtp;
|
||||
struct mgcp_trunk;
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_conn_rtp;
|
||||
|
||||
#define OSMUX_PORT 1984
|
||||
|
||||
enum {
|
||||
OSMUX_ROLE_BSC = 0,
|
||||
OSMUX_ROLE_BSC_NAT,
|
||||
};
|
||||
|
||||
int osmux_init(int role, struct mgcp_config *cfg);
|
||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
struct osmo_sockaddr *addr, uint16_t port);
|
||||
int osmux_init(struct mgcp_trunk *trunk);
|
||||
int osmux_init_conn(struct mgcp_conn_rtp *conn);
|
||||
int conn_osmux_enable(struct mgcp_conn_rtp *conn);
|
||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
|
||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
|
||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
|
||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int conn_osmux_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn);
|
||||
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg);
|
||||
int osmux_send_dummy(struct mgcp_conn_rtp *conn);
|
||||
|
||||
void osmux_cid_pool_get(uint8_t osmux_cid);
|
||||
int osmux_cid_pool_get_next(void);
|
||||
|
@ -29,10 +26,14 @@ int osmux_cid_pool_count_used(void);
|
|||
|
||||
enum osmux_state {
|
||||
OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
|
||||
OSMUX_STATE_ACTIVATING, /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref osmux_enable_endpoint. */
|
||||
OSMUX_STATE_ENABLED, /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
|
||||
OSMUX_STATE_ACTIVATING, /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref conn_osmux_enable. */
|
||||
OSMUX_STATE_ENABLED, /* Osmux was initialized by \ref conn_osmux_enable and can process frames */
|
||||
};
|
||||
|
||||
extern const struct value_string osmux_state_strs[];
|
||||
static inline const char *osmux_state_str(enum osmux_state val)
|
||||
{ return get_value_string(osmux_state_strs, val); }
|
||||
|
||||
enum osmux_usage {
|
||||
OSMUX_USAGE_OFF = 0,
|
||||
OSMUX_USAGE_ON = 1,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include <osmocom/core/defs.h>
|
||||
|
||||
#if BUILDING_LIBOSMOMGCPCLIENT
|
||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text)
|
||||
#else
|
||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text) OSMO_DEPRECATED(text)
|
||||
#endif
|
|
@ -3,14 +3,15 @@
|
|||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/mgcp_client/defs.h>
|
||||
#include <osmocom/mgcp_client/mgcp_common.h>
|
||||
|
||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
|
||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
|
||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
|
||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
|
||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
|
||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
|
||||
|
||||
#define MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP "null"
|
||||
#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
|
||||
|
||||
struct msgb;
|
||||
|
@ -35,6 +36,12 @@ struct mgcp_client_conf {
|
|||
|
||||
/* human readable name / description */
|
||||
char *description;
|
||||
|
||||
struct {
|
||||
uint32_t timeout_sec;
|
||||
uint32_t req_interval_sec;
|
||||
char req_endpoint_name[MGCP_ENDPOINT_MAXLEN];
|
||||
} keepalive;
|
||||
};
|
||||
|
||||
typedef unsigned int mgcp_trans_id_t;
|
||||
|
@ -45,11 +52,12 @@ enum mgcp_codecs {
|
|||
CODEC_GSM_8000_1 = 3,
|
||||
CODEC_PCMA_8000_1 = 8,
|
||||
CODEC_G729_8000_1 = 18,
|
||||
CODEC_GSMEFR_8000_1 = 110,
|
||||
CODEC_GSMHR_8000_1 = 111,
|
||||
CODEC_AMR_8000_1 = 112,
|
||||
CODEC_AMRWB_16000_1 = 113,
|
||||
CODEC_GSMEFR_8000_1 = 110, /* 3GPP TS 48.103 table 5.4.2.2.1 */
|
||||
CODEC_GSMHR_8000_1 = 111, /* 3GPP TS 48.103 table 5.4.2.2.1 */
|
||||
CODEC_AMR_8000_1 = 112, /* 3GPP TS 48.103 table 5.4.2.2.1 */
|
||||
CODEC_AMRWB_16000_1 = 113, /* 3GPP TS 48.103 table 5.4.2.2.1 */
|
||||
CODEC_IUFP = 96,
|
||||
CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
|
||||
};
|
||||
/* Note: when new codec types are added, the corresponding value strings
|
||||
* in mgcp_client.c (codec_table) must be updated as well. Enumerations
|
||||
|
@ -71,27 +79,7 @@ struct ptmap {
|
|||
unsigned int pt;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
|
||||
|
||||
enum mgcp_verb {
|
||||
MGCP_VERB_CRCX,
|
||||
|
@ -101,38 +89,8 @@ enum mgcp_verb {
|
|||
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;
|
||||
};
|
||||
|
||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
|
||||
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_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
|
||||
int mgcp_client_config_write(struct vty *vty, const char *indent);
|
||||
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
|
||||
|
@ -140,7 +98,7 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
|
|||
struct mgcp_client *mgcp_client_init(void *ctx,
|
||||
struct mgcp_client_conf *conf);
|
||||
int mgcp_client_connect(struct mgcp_client *mgcp);
|
||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
|
||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports) OSMO_DEPRECATED("Use mgcp_client_connect() instead");
|
||||
void mgcp_client_disconnect(struct mgcp_client *mgcp);
|
||||
|
||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
|
||||
|
@ -152,20 +110,8 @@ const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
|
|||
const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
|
||||
uint8_t rate, uint8_t offset);
|
||||
|
||||
/* Invoked when an MGCP response is received or sending failed. When the
|
||||
* response is passed as NULL, this indicates failure during transmission. */
|
||||
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
|
||||
int mgcp_response_parse_params(struct mgcp_response *r);
|
||||
|
||||
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
|
||||
mgcp_response_cb_t response_cb, void *priv);
|
||||
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
|
||||
|
||||
enum mgcp_connection_mode;
|
||||
|
||||
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
|
||||
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
|
||||
|
||||
extern const struct value_string mgcp_client_connection_mode_strs[];
|
||||
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,7 @@ static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
|
|||
void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
|
||||
|
||||
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
|
||||
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep);
|
||||
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
|
||||
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
|
||||
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
|
||||
|
|
|
@ -29,11 +29,11 @@ struct mgcp_conn_peer {
|
|||
/*! RTP packetization interval (optional) */
|
||||
unsigned int ptime;
|
||||
|
||||
/*! RTP codec list (optional) */
|
||||
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
|
||||
|
||||
/*! Number of codecs in RTP codec list (optional) */
|
||||
unsigned int codecs_len;
|
||||
/*! Deprecated. Use only ptmap[].codec in new code. */
|
||||
enum mgcp_codecs codecs[MGCP_MAX_CODECS]
|
||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
|
||||
unsigned int codecs_len
|
||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
|
||||
|
||||
/*! RTP payload type map (optional, only needed when payload types are
|
||||
* used that differ from what IANA/3GPP defines) */
|
||||
|
@ -64,11 +64,15 @@ struct mgcp_conn_peer {
|
|||
};
|
||||
|
||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
|
||||
uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
|
||||
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);
|
||||
uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
|
||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_alloc() and osmo_mgcpc_ep_ci_add() instead");
|
||||
int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
|
||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_request() instead");
|
||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi)
|
||||
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_dlcx() instead");
|
||||
|
||||
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);
|
||||
|
||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/osmo_io.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
|
||||
#define MSGB_CB_MGCP_TRANS_ID 0
|
||||
|
||||
|
@ -12,18 +13,39 @@ struct reset_ep {
|
|||
|
||||
struct mgcp_client {
|
||||
struct mgcp_client_conf actual;
|
||||
struct osmo_wqueue wq;
|
||||
struct osmo_io_fd *iofd;
|
||||
mgcp_trans_id_t next_trans_id;
|
||||
struct llist_head responses_pending;
|
||||
struct llist_head inuse_endpoints;
|
||||
struct mgcp_client_pool *pool;
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
struct osmo_timer_list keepalive_tx_timer;
|
||||
struct osmo_timer_list keepalive_rx_timer;
|
||||
bool conn_up;
|
||||
};
|
||||
|
||||
struct mgcp_inuse_endpoint {
|
||||
struct llist_head entry;
|
||||
uint16_t id;
|
||||
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 llist_head entry;
|
||||
|
||||
|
@ -39,3 +61,41 @@ struct mgcp_response_pending * mgcp_client_pending_add(
|
|||
mgcp_trans_id_t trans_id,
|
||||
mgcp_response_cb_t response_cb,
|
||||
void *priv);
|
||||
|
||||
#define MGCP_MSG_PRESENCE_ENDPOINT 0x0001
|
||||
#define MGCP_MSG_PRESENCE_CALL_ID 0x0002
|
||||
#define MGCP_MSG_PRESENCE_CONN_ID 0x0004
|
||||
#define MGCP_MSG_PRESENCE_AUDIO_IP 0x0008
|
||||
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
|
||||
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
|
||||
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
|
||||
#define MGCP_MSG_PRESENCE_X_OSMO_IGN 0x8000
|
||||
|
||||
struct mgcp_msg {
|
||||
enum mgcp_verb verb;
|
||||
/* See MGCP_MSG_PRESENCE_* constants */
|
||||
uint32_t presence;
|
||||
char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||
unsigned int call_id;
|
||||
char *conn_id;
|
||||
uint16_t audio_port;
|
||||
char *audio_ip;
|
||||
enum mgcp_connection_mode conn_mode;
|
||||
unsigned int ptime;
|
||||
struct ptmap ptmap[MGCP_MAX_CODECS];
|
||||
unsigned int ptmap_len;
|
||||
uint32_t x_osmo_ign;
|
||||
bool x_osmo_osmux_use;
|
||||
int x_osmo_osmux_cid; /* -1 is wildcard */
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
int mgcp_response_parse_params(struct mgcp_response *r);
|
||||
|
||||
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
|
||||
mgcp_response_cb_t response_cb, void *priv);
|
||||
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
|
||||
|
||||
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
|
||||
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/vty/vty.h>
|
||||
|
||||
struct mgcp_client;
|
||||
struct mgcp_client_pool;
|
||||
struct mgcp_client_pool_member;
|
||||
|
||||
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
|
||||
|
||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
|
||||
int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
|
||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
|
||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
|
||||
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool);
|
||||
|
||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
|
||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
|
||||
|
||||
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr);
|
||||
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member);
|
||||
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);
|
||||
|
|
|
@ -1,9 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
/* Struct to handle a pool of MGWs. (Use _pool functions) */
|
||||
struct mgcp_client_pool {
|
||||
|
||||
/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
|
||||
* mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
|
||||
struct mgcp_client *mgcp_client_single;
|
||||
|
||||
/* A list that manages the pool members (see mgcp_client_pool_member->list above) */
|
||||
struct llist_head member_list;
|
||||
|
||||
/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
|
||||
* mgcp_client_pool_vty_init() */
|
||||
char *vty_indent;
|
||||
|
||||
/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
|
||||
struct cmd_node *vty_node;
|
||||
};
|
||||
|
||||
/* Struct to handle a member of a pool of MGWs. */
|
||||
struct mgcp_client_pool_member {
|
||||
/* Entry in llist mgcp_client_pool->pool. */
|
||||
struct llist_head list;
|
||||
|
||||
/* The pool managing this object: */
|
||||
struct mgcp_client_pool *pool;
|
||||
|
||||
/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
|
||||
* the log. */
|
||||
unsigned int nr;
|
||||
|
@ -24,22 +46,7 @@ struct mgcp_client_pool_member {
|
|||
unsigned int refcount;
|
||||
};
|
||||
|
||||
/* Struct to handle a pool of MGWs. (Use _pool functions) */
|
||||
struct mgcp_client_pool {
|
||||
|
||||
/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
|
||||
* mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
|
||||
struct mgcp_client *mgcp_client_single;
|
||||
|
||||
/* A list that manages the pool members (see above) */
|
||||
struct llist_head pool;
|
||||
|
||||
/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
|
||||
* mgcp_client_pool_vty_init() */
|
||||
char *vty_indent;
|
||||
|
||||
/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
|
||||
struct cmd_node *vty_node;
|
||||
};
|
||||
|
||||
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr);
|
||||
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member);
|
||||
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member);
|
||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
|
||||
|
|
|
@ -13,12 +13,6 @@ AM_CFLAGS = \
|
|||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
# Libraries
|
||||
SUBDIRS = \
|
||||
libosmo-mgcp-client \
|
||||
|
|
|
@ -14,14 +14,12 @@ AM_CFLAGS = \
|
|||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
# This is not at all related to the release version, but a range of supported
|
||||
# API versions. Read TODO_RELEASE in the source tree's root!
|
||||
MGCP_CLIENT_LIBVERSION=10:0:1
|
||||
MGCP_CLIENT_LIBVERSION=13:0:1
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libosmo-mgcp-client.la \
|
||||
|
@ -35,4 +33,13 @@ libosmo_mgcp_client_la_SOURCES = \
|
|||
mgcp_client_pool.c \
|
||||
$(NULL)
|
||||
|
||||
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
|
||||
libosmo_mgcp_client_la_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-version-info $(MGCP_CLIENT_LIBVERSION) \
|
||||
-no-undefined \
|
||||
$(NULL)
|
||||
|
||||
libosmo_mgcp_client_la_LIBADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(NULL)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -173,6 +173,30 @@ const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
|
|||
return osmo_fsm_inst_name(ep->fi);
|
||||
}
|
||||
|
||||
/*! Get "local endpoint name" part of the endpoint name: (local-endpoint-name@domain-name)
|
||||
*
|
||||
* \param ep The MGCP Endpoint
|
||||
* \returns the local endpoint name if found, NULL on error.
|
||||
*/
|
||||
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep)
|
||||
{
|
||||
static char buf[1024];
|
||||
const char *sep;
|
||||
|
||||
OSMO_ASSERT(ep);
|
||||
sep = strchr(ep->endpoint, '@');
|
||||
if (!sep) {
|
||||
OSMO_STRLCPY_ARRAY(buf, ep->endpoint);
|
||||
return buf;
|
||||
}
|
||||
if (sep - ep->endpoint >= sizeof(buf))
|
||||
return NULL;
|
||||
|
||||
memcpy(buf, ep->endpoint, sep - ep->endpoint);
|
||||
buf[sep - ep->endpoint] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
|
||||
{
|
||||
/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
|
||||
|
@ -227,7 +251,7 @@ static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
|
|||
|
||||
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
|
||||
|
||||
static void fill_event_names()
|
||||
static void fill_event_names(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
|
||||
|
@ -243,7 +267,7 @@ static void fill_event_names()
|
|||
}
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
|
||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
|
||||
fill_event_names();
|
||||
|
@ -509,10 +533,42 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
|
|||
mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
|
||||
ci->notify.fi ? "" : " (not sending a notification)");
|
||||
|
||||
/* Below ordering is a delicate decision:
|
||||
*
|
||||
* We want to
|
||||
* - emit the resulting event to ci->notify.fi,
|
||||
* - check whether we want to tx the next pending MGCP message.
|
||||
* Both these steps may terminate (=deallocate) the ep.
|
||||
* So whichever one goes first may cause a use-after-free in the other.
|
||||
*
|
||||
* When dispatching the FSM event, we don't get an rc indicating dealloc of the FSM -- it may deallocate and we
|
||||
* cannot tell. The common mechanism for that is osmo_fsm_set_dealloc_ctx(OTC_SELECT) and query the still
|
||||
* allocated FSM state after termination (here we would check 'if (ci->ep != NULL)'), but we cannot assume the
|
||||
* caller has actually set up an osmo_fsm_set_dealloc_ctx(). At time of writing, e.g. osmo-hnbgw does not use
|
||||
* it.
|
||||
*
|
||||
* In osmo_mgcpc_ep_fsm_check_state_chg_after_response(), we do get an rc: false means FSM has terminated.
|
||||
* On termination, the ep emits a term event to the FSM's parent.
|
||||
* That may cause the notify.fi to be terminated in turn, depending on how the caller set things up.
|
||||
* So: we cannot store notify.fi before, then call osmo_mgcpc_ep_fsm_check_state_chg_after_response(), and then
|
||||
* emit the event, because notify.fi may have deallocated. We cannot look up whether
|
||||
* osmo_mgcpc_ep_cancel_notify() has been called, because ci may have deallocated along with ci->ep.
|
||||
*
|
||||
* We have to skip emitting below success event in case the ep is now terminated.
|
||||
* - It may be the final DLCX OK: not a problem, osmo_mgcpc_ep_ci_dlcx() has no notify args on purpose, so we do
|
||||
* make all callers not set a notify event for DLCX by design. notify.fi should always be NULL when the final
|
||||
* DLCX OK terminates the local endpoint state.
|
||||
* - It may also be sudden termination due to a bad problem, in which case we shouldn't emit success.
|
||||
* The osmo_fsm_inst.parent_term_event should suffice as feedback to the caller.
|
||||
*/
|
||||
|
||||
if (osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi) == false) {
|
||||
/* false means, the ci->ep has been terminated. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (ci->notify.fi)
|
||||
osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
|
||||
|
||||
osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
|
||||
}
|
||||
|
||||
/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
|
||||
|
@ -662,11 +718,11 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
|
|||
osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
|
||||
*ci = cleared_ci;
|
||||
|
||||
LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
|
||||
|
||||
if (verb_info)
|
||||
ci->verb_info = *verb_info;
|
||||
|
||||
LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
|
||||
|
||||
if (ep->endpoint[0]) {
|
||||
if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
|
||||
LOG_CI(ci, LOGL_ERROR,
|
||||
|
@ -997,7 +1053,7 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
static void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
int i;
|
||||
struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
@ -114,12 +115,10 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
|
|||
.call_id = info->call_id,
|
||||
.conn_mode = MGCP_CONN_RECV_ONLY,
|
||||
.ptime = info->ptime,
|
||||
.codecs_len = info->codecs_len,
|
||||
.ptmap_len = info->ptmap_len,
|
||||
.param_present = info->param_present
|
||||
};
|
||||
osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
|
||||
memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
|
||||
memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
|
||||
memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
|
||||
|
||||
|
@ -136,10 +135,19 @@ 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)
|
||||
{
|
||||
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT;
|
||||
mgcp_msg->audio_ip = info->addr;
|
||||
mgcp_msg->audio_port = info->port;
|
||||
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
|
||||
bool ip_is_set = info->addr[0] != '\0' &&
|
||||
strncmp(info->addr, "::", sizeof(info->addr)) != 0 &&
|
||||
strncmp(info->addr, "0.0.0.0", sizeof(info->addr)) != 0;
|
||||
if (ip_is_set) {
|
||||
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP;
|
||||
mgcp_msg->audio_ip = info->addr;
|
||||
}
|
||||
if (info->port) {
|
||||
mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_PORT;
|
||||
mgcp_msg->audio_port = info->port;
|
||||
}
|
||||
if (ip_is_set && info->port)
|
||||
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
|
||||
}
|
||||
|
||||
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
|
||||
|
@ -163,12 +171,10 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
|||
.audio_ip = mgcp_ctx->conn_peer_local.addr,
|
||||
.audio_port = mgcp_ctx->conn_peer_local.port,
|
||||
.ptime = mgcp_ctx->conn_peer_local.ptime,
|
||||
.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
|
||||
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
|
||||
.param_present = mgcp_ctx->conn_peer_local.param_present
|
||||
};
|
||||
osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
|
||||
memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
|
||||
memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
|
||||
memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
|
||||
|
||||
|
@ -221,8 +227,7 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||
mgcp_ctx->conn_peer_local.endpoint);
|
||||
|
||||
make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
if (mgcp_ctx->conn_peer_local.port)
|
||||
add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
|
||||
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
||||
|
@ -364,13 +369,21 @@ static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||
switch (event) {
|
||||
case EV_MDCX:
|
||||
msg = make_mdcx_msg(mgcp_ctx);
|
||||
OSMO_ASSERT(msg);
|
||||
if (!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);
|
||||
new_state = ST_MDCX_RESP;
|
||||
break;
|
||||
case EV_DLCX:
|
||||
msg = make_dlcx_msg(mgcp_ctx);
|
||||
OSMO_ASSERT(msg);
|
||||
if (!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);
|
||||
new_state = ST_DLCX_RESP;
|
||||
break;
|
||||
|
@ -611,6 +624,72 @@ static struct osmo_fsm fsm_mgcp_client = {
|
|||
.log_subsys = DLMGCP,
|
||||
};
|
||||
|
||||
/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
|
||||
* that has codecs[] set, apply it to ptmap[] instead. */
|
||||
static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)
|
||||
{
|
||||
struct ptmap ptmap[MGCP_MAX_CODECS];
|
||||
unsigned int ptmap_len;
|
||||
|
||||
if (!conn_peer->codecs_len)
|
||||
return;
|
||||
|
||||
/* Before dropping codecs[], codecs[] would indicate the order in which the codecs should appear in SDP. ptmap[]
|
||||
* would indicate payload type numbers when not using a default payload type number (may omit entries).
|
||||
* Now, ptmap[] just indicates both at the same time; codecs[] should be empty, and ptmap[] lists all codecs.
|
||||
* So if any codecs[] are present, recreate ptmap[] in the order of codecs[]. */
|
||||
|
||||
ptmap_len = 0;
|
||||
for (int i = 0; i < conn_peer->codecs_len; i++) {
|
||||
enum mgcp_codecs codec = conn_peer->codecs[i];
|
||||
struct ptmap *found = NULL;
|
||||
|
||||
/* Look up whether a specific pt was indicated for this codec */
|
||||
for (int p = 0; p < conn_peer->ptmap_len; p++) {
|
||||
if (conn_peer->ptmap[p].codec != codec)
|
||||
continue;
|
||||
found = &conn_peer->ptmap[p];
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
ptmap[ptmap_len] = *found;
|
||||
} else {
|
||||
ptmap[ptmap_len] = (struct ptmap){
|
||||
.codec = codec,
|
||||
/* some enum mgcp_codecs correspond to their standard PT nr, so for compat: */
|
||||
.pt = codec,
|
||||
};
|
||||
}
|
||||
ptmap_len++;
|
||||
}
|
||||
|
||||
/* Are there any entries in the old ptmap that were omitted by codecs[]? */
|
||||
for (int p = 0; p < conn_peer->ptmap_len; p++) {
|
||||
bool exists = false;
|
||||
for (int i = 0; i < ptmap_len; i++) {
|
||||
if (ptmap_cmp(&ptmap[i], &conn_peer->ptmap[p]))
|
||||
continue;
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
continue;
|
||||
|
||||
if (ptmap_len >= ARRAY_SIZE(ptmap))
|
||||
break;
|
||||
|
||||
/* Not present yet, add it to the end */
|
||||
ptmap[ptmap_len] = conn_peer->ptmap[p];
|
||||
ptmap_len++;
|
||||
}
|
||||
|
||||
/* Use the new ptmap[], and clear out legacy codecs[]. */
|
||||
memcpy(conn_peer->ptmap, ptmap, sizeof(conn_peer->ptmap));
|
||||
conn_peer->ptmap_len = ptmap_len;
|
||||
conn_peer->codecs_len = 0;
|
||||
}
|
||||
|
||||
/*! allocate FSM, and create a new connection on the MGW.
|
||||
* \param[in] mgcp MGCP client descriptor.
|
||||
* \param[in] parent_fi Parent FSM instance.
|
||||
|
@ -625,6 +704,7 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
|
|||
struct osmo_fsm_inst *fi;
|
||||
struct in6_addr ip_test;
|
||||
|
||||
mgcp_conn_peer_compat(conn_peer);
|
||||
|
||||
OSMO_ASSERT(parent_fi);
|
||||
OSMO_ASSERT(mgcp);
|
||||
|
@ -664,6 +744,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
|
|||
struct mgcp_ctx *mgcp_ctx = fi->priv;
|
||||
struct in6_addr ip_test;
|
||||
|
||||
mgcp_conn_peer_compat(conn_peer);
|
||||
|
||||
OSMO_ASSERT(mgcp_ctx);
|
||||
OSMO_ASSERT(conn_peer);
|
||||
|
||||
|
@ -760,7 +842,7 @@ const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
|
||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <asm-generic/errno.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
|
||||
|
@ -27,32 +28,6 @@
|
|||
#define LOGPPMGW(pool_member, level, fmt, args...) \
|
||||
LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
|
||||
|
||||
/* Get a human readable name for a given pool member. */
|
||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
const struct mgcp_client *mpcp_client;
|
||||
struct mgcp_client mpcp_client_dummy;
|
||||
static char name[512];
|
||||
const char *description;
|
||||
|
||||
if (!pool_member)
|
||||
return "(null)";
|
||||
|
||||
/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
|
||||
* initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
|
||||
if (!pool_member->client) {
|
||||
memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
|
||||
mpcp_client = &mpcp_client_dummy;
|
||||
} else {
|
||||
mpcp_client = pool_member->client;
|
||||
}
|
||||
|
||||
description = mgcp_client_name(mpcp_client);
|
||||
snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
|
||||
* mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
|
||||
* \param[in] talloc_ctx talloc context. */
|
||||
|
@ -64,7 +39,7 @@ struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
|
|||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
INIT_LLIST_HEAD(&pool->pool);
|
||||
INIT_LLIST_HEAD(&pool->member_list);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
@ -77,29 +52,11 @@ unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
|
|||
struct mgcp_client_pool_member *pool_member;
|
||||
unsigned int pool_members_initialized = 0;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
llist_for_each_entry(pool_member, &pool->member_list, list) {
|
||||
|
||||
/* Initialize client */
|
||||
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
|
||||
if (!pool_member->client) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set backpointer so that we can detect later that this MGCP client is managed
|
||||
* by this pool. */
|
||||
pool_member->client->pool = pool;
|
||||
|
||||
/* Connect client */
|
||||
if (mgcp_client_connect2(pool_member->client, 0)) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
|
||||
pool_member->conf.remote_addr, pool_member->conf.remote_port);
|
||||
talloc_free(pool_member->client);
|
||||
pool_member->client = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
pool_members_initialized++;
|
||||
if (mgcp_client_pool_member_reinit_client(pool_member) == 0)
|
||||
pool_members_initialized++;
|
||||
}
|
||||
|
||||
return pool_members_initialized;
|
||||
|
@ -118,23 +75,43 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
|
|||
pool->mgcp_client_single = mgcp_client;
|
||||
}
|
||||
|
||||
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool)
|
||||
{
|
||||
return llist_empty(&pool->member_list);
|
||||
}
|
||||
|
||||
/*! Lookup the selected MGCP client config by its reference number */
|
||||
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->member_list, list) {
|
||||
if (pool_member->nr == nr)
|
||||
return pool_member;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
|
||||
* pool member that is suitable (has a client, is not blocked, has a low load). */
|
||||
* pool member that is suitable (is not blocked, has a client with a working link, has a low load). */
|
||||
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
struct mgcp_client_pool_member *pool_member_picked = NULL;
|
||||
unsigned int n_pool_members = llist_count(&pool->pool);
|
||||
unsigned int n_pool_members = 0;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
if (pool_member->blocked == false && pool_member->client) {
|
||||
llist_for_each_entry(pool_member, &pool->member_list, list) {
|
||||
n_pool_members++;
|
||||
bool conn_up = pool_member->client && pool_member->client->conn_up;
|
||||
if (pool_member->blocked == false && conn_up) {
|
||||
if (!pool_member_picked)
|
||||
pool_member_picked = pool_member;
|
||||
else if (pool_member_picked->refcount > pool_member->refcount)
|
||||
pool_member_picked = pool_member;
|
||||
} else {
|
||||
LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
|
||||
pool_member->nr);
|
||||
LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u, link=%u)\n",
|
||||
__func__, pool_member->nr, pool_member->blocked, !!pool_member->client, conn_up);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,26 +140,24 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
|
|||
* by the application code. */
|
||||
|
||||
/* When the pool is empty, return a single MGCP client if it is registered. */
|
||||
if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
|
||||
if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
|
||||
mgcp_client_name(pool->mgcp_client_single));
|
||||
return pool->mgcp_client_single;
|
||||
}
|
||||
|
||||
/* Abort when the pool is empty */
|
||||
if (llist_empty(&pool->pool)) {
|
||||
if (llist_empty(&pool->member_list)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pick a suitable pool member */
|
||||
pool_member = mgcp_client_pool_pick(pool);
|
||||
if (pool_member) {
|
||||
pool_member->refcount++;
|
||||
return pool_member->client;
|
||||
}
|
||||
if (!pool_member)
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
return mgcp_client_pool_member_get(pool_member);
|
||||
}
|
||||
|
||||
/*! put an MGCP client back into the pool (decrement reference counter).
|
||||
|
@ -194,23 +169,130 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
|
|||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
struct mgcp_client_pool *pool;
|
||||
|
||||
if (!mgcp_client)
|
||||
return;
|
||||
|
||||
if (mgcp_client->pool)
|
||||
pool = mgcp_client->pool;
|
||||
else
|
||||
if (!mgcp_client->pool_member)
|
||||
return;
|
||||
pool_member = mgcp_client->pool_member;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
if (pool_member->client == mgcp_client) {
|
||||
if (pool_member->refcount == 0) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
|
||||
return;
|
||||
}
|
||||
pool_member->refcount--;
|
||||
}
|
||||
if (pool_member->refcount == 0) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
|
||||
return;
|
||||
}
|
||||
pool_member->refcount--;
|
||||
}
|
||||
|
||||
/***************************
|
||||
* mgcp_client_pool_member:
|
||||
***************************/
|
||||
|
||||
/*! Allocate an mgcp_client_pool_member.
|
||||
* \param[in] pool MGCP client pool descriptor.
|
||||
* \param[in] nr Reference number of the pool member.
|
||||
*/
|
||||
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
pool_member = talloc_zero(pool, struct mgcp_client_pool_member);
|
||||
OSMO_ASSERT(pool_member);
|
||||
mgcp_client_conf_init(&pool_member->conf);
|
||||
pool_member->pool = pool;
|
||||
pool_member->nr = nr;
|
||||
llist_add_tail(&pool_member->list, &pool->member_list);
|
||||
return pool_member;
|
||||
}
|
||||
|
||||
/*! Free an mgcp_client_pool_member allocated through mgcp_client_pool_member_alloc().
|
||||
* \param[in] pool_member MGCP client pool descriptor.
|
||||
*
|
||||
* It also frees the associated MGCP client if present.
|
||||
*/
|
||||
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
llist_del(&pool_member->list);
|
||||
if (pool_member->client) {
|
||||
mgcp_client_disconnect(pool_member->client);
|
||||
talloc_free(pool_member->client);
|
||||
}
|
||||
talloc_free(pool_member);
|
||||
}
|
||||
|
||||
/*! Recreate and reconnect the MGCP client associated to the pool descriptor.
|
||||
* \param[in] pool_member MGCP client pool descriptor.
|
||||
*/
|
||||
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
/* Get rid of a possibly existing old MGCP client instance first */
|
||||
if (pool_member->client) {
|
||||
mgcp_client_disconnect(pool_member->client);
|
||||
talloc_free(pool_member->client);
|
||||
}
|
||||
|
||||
/* Initialize client */
|
||||
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
|
||||
if (!pool_member->client) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
|
||||
pool_member->client->pool_member = pool_member;
|
||||
|
||||
/* Connect client */
|
||||
if (mgcp_client_connect(pool_member->client)) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
|
||||
pool_member->conf.remote_addr, pool_member->conf.remote_port);
|
||||
talloc_free(pool_member->client);
|
||||
pool_member->client = NULL;
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a human readable name for a given pool member. */
|
||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
const struct mgcp_client *mpcp_client;
|
||||
struct mgcp_client mpcp_client_dummy;
|
||||
static char name[512];
|
||||
const char *description;
|
||||
|
||||
if (!pool_member)
|
||||
return "(null)";
|
||||
|
||||
/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
|
||||
* initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
|
||||
if (!pool_member->client) {
|
||||
memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
|
||||
mpcp_client = &mpcp_client_dummy;
|
||||
} else {
|
||||
mpcp_client = pool_member->client;
|
||||
}
|
||||
|
||||
description = mgcp_client_name(mpcp_client);
|
||||
snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*! Get the MGCP client associated with the pool reference from the pool (increment reference counter).
|
||||
* \param[in] pool_member MGCP client pool descriptor.
|
||||
* \returns MGCP client descriptor, NULL if no member was not ready.
|
||||
*/
|
||||
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
pool_member->refcount++;
|
||||
return pool_member->client;
|
||||
}
|
||||
|
||||
/*! Get whether the MGCP client associated with the pool reference is blocked by policy.
|
||||
* \param[in] pool_member MGCP client pool descriptor.
|
||||
* \returns true if blocked, false otherwise
|
||||
*/
|
||||
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member)
|
||||
{
|
||||
return pool_member->blocked;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* MGCP client interface to quagga VTY */
|
||||
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
|
||||
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2009-2011 by Holger Hans Peter Freyther
|
||||
|
@ -28,14 +28,16 @@
|
|||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_pool.h>
|
||||
|
||||
#define MGW_STR MGCP_CLIENT_MGW_STR
|
||||
|
||||
/* Only common (non-pooled) VTY connands will use this talloc context. All
|
||||
/* Only common (non-pooled) VTY commands will use this talloc context. All
|
||||
* pooled VTY commands will use the pool (global_mgcp_client_pool) as
|
||||
* talloc context. */
|
||||
static void *global_mgcp_client_ctx = NULL;
|
||||
|
@ -47,17 +49,46 @@ static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
|
|||
/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
|
||||
static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
|
||||
|
||||
struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
|
||||
static struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
|
||||
{
|
||||
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
|
||||
return vty->index;
|
||||
else
|
||||
return global_mgcp_client_conf;
|
||||
|
||||
/* Global single MGCP config, deprecated: */
|
||||
vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
|
||||
"You should consider reading the User Manual and migrating to 'mgw' node.%s",
|
||||
VTY_NEWLINE);
|
||||
|
||||
return global_mgcp_client_conf;
|
||||
}
|
||||
|
||||
static struct mgcp_client *get_mgcp_client(struct vty *vty)
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node) {
|
||||
llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
|
||||
/* Find matching the conf pointer: */
|
||||
if (&pool_member->conf != conf)
|
||||
continue;
|
||||
return pool_member->client;
|
||||
}
|
||||
}
|
||||
|
||||
/* Global single MGCP config, deprecated: */
|
||||
vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
|
||||
"You should consider reading the User Manual and migrating to 'mgw' node.%s",
|
||||
VTY_NEWLINE);
|
||||
|
||||
/* There's no way to obtain the struct mgcp_client in old interface, but anyway it's deprecated. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
|
||||
"mgw local-ip " VTY_IPV46_CMD,
|
||||
MGW_STR "local bind to connect to MGW from\n"
|
||||
"local-ip " VTY_IPV46_CMD,
|
||||
"local bind to connect to MGW from\n"
|
||||
"local bind IPv4 address\n"
|
||||
"local bind IPv6 address\n")
|
||||
{
|
||||
|
@ -72,10 +103,16 @@ ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
|
|||
"mgcpgw local-ip A.B.C.D",
|
||||
MGW_STR "local bind to connect to MGCP gateway with\n"
|
||||
"local bind IP address\n")
|
||||
ALIAS_DEPRECATED(cfg_mgw_local_ip,
|
||||
cfg_mgw_mgw_local_ip_cmd,
|
||||
"mgw local-ip " VTY_IPV46_CMD,
|
||||
MGW_STR "local bind to connect to MGW from\n"
|
||||
"local bind IPv4 address\n"
|
||||
"local bind IPv6 address\n")
|
||||
|
||||
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
|
||||
"mgw local-port <0-65535>",
|
||||
MGW_STR "local port to connect to MGW from\n"
|
||||
"local-port <0-65535>",
|
||||
"local port to connect to MGW from\n"
|
||||
"local bind port\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
@ -87,10 +124,15 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
|
|||
"mgcpgw local-port <0-65535>",
|
||||
MGW_STR "local bind to connect to MGCP gateway with\n"
|
||||
"local bind port\n")
|
||||
ALIAS_DEPRECATED(cfg_mgw_local_port,
|
||||
cfg_mgw_mgw_local_port_cmd,
|
||||
"mgw local-port <0-65535>",
|
||||
MGW_STR "local port to connect to MGW from\n"
|
||||
"local bind port\n")
|
||||
|
||||
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
|
||||
"mgw remote-ip " VTY_IPV46_CMD,
|
||||
MGW_STR "remote IP address to reach the MGW at\n"
|
||||
"remote-ip " VTY_IPV46_CMD,
|
||||
"remote IP address to reach the MGW at\n"
|
||||
"remote IPv4 address\n"
|
||||
"remote IPv6 address\n")
|
||||
{
|
||||
|
@ -104,10 +146,16 @@ ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
|
|||
"mgcpgw remote-ip A.B.C.D",
|
||||
MGW_STR "remote bind to connect to MGCP gateway with\n"
|
||||
"remote bind IP address\n")
|
||||
ALIAS_DEPRECATED(cfg_mgw_remote_ip,
|
||||
cfg_mgw_mgw_remote_ip_cmd,
|
||||
"mgw remote-ip " VTY_IPV46_CMD,
|
||||
MGW_STR "remote IP address to reach the MGW at\n"
|
||||
"remote IPv4 address\n"
|
||||
"remote IPv6 address\n")
|
||||
|
||||
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
|
||||
"mgw remote-port <0-65535>",
|
||||
MGW_STR "remote port to reach the MGW at\n"
|
||||
"remote-port <0-65535>",
|
||||
"remote port to reach the MGW at\n"
|
||||
"remote port\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
@ -119,8 +167,13 @@ ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
|
|||
"mgcpgw remote-port <0-65535>",
|
||||
MGW_STR "remote bind to connect to MGCP gateway with\n"
|
||||
"remote bind port\n")
|
||||
ALIAS_DEPRECATED(cfg_mgw_remote_port,
|
||||
cfg_mgw_mgw_remote_port_cmd,
|
||||
"mgw remote-port <0-65535>",
|
||||
MGW_STR "remote port to reach the MGW at\n"
|
||||
"remote port\n")
|
||||
|
||||
DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
|
||||
DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
|
||||
"mgw endpoint-range <1-65534> <1-65534>",
|
||||
MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
|
||||
"-\n" "-\n")
|
||||
|
@ -130,7 +183,7 @@ DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
|
|||
VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
|
||||
ALIAS_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
|
||||
"mgcpgw endpoint-range <1-65534> <1-65534>",
|
||||
MGW_STR "usable range of endpoint identifiers\n"
|
||||
"set first useable endpoint identifier\n"
|
||||
|
@ -158,8 +211,8 @@ ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
|
|||
|
||||
DEFUN(cfg_mgw_endpoint_domain_name,
|
||||
cfg_mgw_endpoint_domain_name_cmd,
|
||||
"mgw endpoint-domain NAME",
|
||||
MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
|
||||
"endpoint-domain NAME",
|
||||
"Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
|
||||
"Domain name, should be alphanumeric.\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
@ -172,11 +225,16 @@ DEFUN(cfg_mgw_endpoint_domain_name,
|
|||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_endpoint_domain_name,
|
||||
cfg_mgw_mgw_endpoint_domain_name_cmd,
|
||||
"mgw endpoint-domain NAME",
|
||||
MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
|
||||
"Domain name, should be alphanumeric.\n")
|
||||
|
||||
DEFUN(cfg_mgw_reset_ep_name,
|
||||
cfg_mgw_reset_ep_name_cmd,
|
||||
"mgw reset-endpoint NAME",
|
||||
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
|
||||
"reset-endpoint NAME",
|
||||
"Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
|
||||
"e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
{
|
||||
|
@ -214,11 +272,17 @@ DEFUN(cfg_mgw_reset_ep_name,
|
|||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_reset_ep_name,
|
||||
cfg_mgw_mgw_reset_ep_name_cmd,
|
||||
"mgw reset-endpoint NAME",
|
||||
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
|
||||
"e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
|
||||
DEFUN(cfg_mgw_no_reset_ep_name,
|
||||
cfg_mgw_no_reset_ep_name_cmd,
|
||||
"no mgw reset-endpoint NAME",
|
||||
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
|
||||
"no reset-endpoint NAME",
|
||||
NO_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
{
|
||||
struct reset_ep *reset_ep;
|
||||
|
@ -235,6 +299,96 @@ DEFUN(cfg_mgw_no_reset_ep_name,
|
|||
vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
|
||||
cfg_mgw_mgw_no_reset_ep_name_cmd,
|
||||
"no mgw reset-endpoint NAME",
|
||||
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
|
||||
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
|
||||
|
||||
DEFUN(cfg_mgw_mgw_keepalive_req_interval,
|
||||
cfg_mgw_mgw_keepalive_req_interval_cmd,
|
||||
"keepalive request-interval <0-4294967295>",
|
||||
"Monitor if the MGCP link against MGW is still usable\n"
|
||||
"Send an MGCP command to the MGW at given interval if no other commands are sent\n"
|
||||
"The interval at which send MGCP commands (s), 0 to disable\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
struct mgcp_client *mgcp = get_mgcp_client(vty);
|
||||
|
||||
conf->keepalive.req_interval_sec = atoi(argv[0]);
|
||||
|
||||
if (!mgcp)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* If client already exists, apply the change immediately if possible: */
|
||||
mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
|
||||
if (mgcp->iofd) { /* UDP MGCP socket connected */
|
||||
if (mgcp->actual.keepalive.req_interval_sec > 0) {
|
||||
/* Re-schedule: */
|
||||
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
|
||||
} else {
|
||||
if (osmo_timer_pending(&mgcp->keepalive_tx_timer))
|
||||
osmo_timer_del(&mgcp->keepalive_tx_timer);
|
||||
/* Assume link is UP by default, so that this MGW can be selected: */
|
||||
mgcp->conn_up = true;
|
||||
}
|
||||
} /* else: wait until connect() to do first scheduling */
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_mgw_keepalive_req_endpoint,
|
||||
cfg_mgw_mgw_keepalive_req_endpoint_cmd,
|
||||
"keepalive request-endpoint NAME",
|
||||
"Monitor if the MGCP link against MGW is still usable\n"
|
||||
"Use a given endpoint name when sending an MGCP command to the MGW for keepalive purposes\n"
|
||||
"The name of the endpoint to use\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
struct mgcp_client *mgcp = get_mgcp_client(vty);
|
||||
|
||||
OSMO_STRLCPY_ARRAY(conf->keepalive.req_endpoint_name, argv[0]);
|
||||
|
||||
if (!mgcp)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* If client already exists, apply the change immediately if possible: */
|
||||
OSMO_STRLCPY_ARRAY(mgcp->actual.keepalive.req_endpoint_name, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_mgw_keepalive_timeout,
|
||||
cfg_mgw_mgw_keepalive_timeout_cmd,
|
||||
"keepalive timeout <0-4294967295>",
|
||||
"Monitor if the MGCP link against MGW is still usable\n"
|
||||
"Consider the link to the MGW to be down after time without receiving any message from it\n"
|
||||
"The timeout (s), 0 to disable\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
struct mgcp_client *mgcp = get_mgcp_client(vty);
|
||||
|
||||
conf->keepalive.timeout_sec = atoi(argv[0]);
|
||||
|
||||
if (!mgcp)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* If client already exists, apply the change immediately if possible: */
|
||||
mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
|
||||
if (mgcp->iofd) { /* UDP MGCP socket connected */
|
||||
if (mgcp->actual.keepalive.timeout_sec > 0) {
|
||||
/* Re-schedule: */
|
||||
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
|
||||
} else {
|
||||
if (osmo_timer_pending(&mgcp->keepalive_rx_timer))
|
||||
osmo_timer_del(&mgcp->keepalive_rx_timer);
|
||||
/* Assume link is UP by default, so that this MGW can be selected: */
|
||||
mgcp->conn_up = true;
|
||||
}
|
||||
} /* else: wait until connect() to do first scheduling */
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
|
||||
{
|
||||
|
@ -242,33 +396,47 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
|
|||
int port;
|
||||
struct reset_ep *reset_ep;
|
||||
|
||||
if (conf->description)
|
||||
/* If caller doesn't the MGW pool API (mgcp_client_pool_vty_init was never called),
|
||||
* then the "mgw" cmd prefix must be added since the old node always contained it.
|
||||
*/
|
||||
const char *mgw_prefix = global_mgcp_client_pool ? "" : "mgw ";
|
||||
|
||||
if (conf->description) /* description never had "mgw" prefix even on old node: */
|
||||
vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
|
||||
|
||||
addr = conf->local_addr;
|
||||
if (addr)
|
||||
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, "%s%slocal-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
|
||||
port = conf->local_port;
|
||||
if (port >= 0)
|
||||
vty_out(vty, "%smgw local-port %u%s", indent,
|
||||
vty_out(vty, "%s%slocal-port %u%s", indent, mgw_prefix,
|
||||
(uint16_t)port, VTY_NEWLINE);
|
||||
|
||||
addr = conf->remote_addr;
|
||||
if (addr)
|
||||
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, "%s%sremote-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
|
||||
port = conf->remote_port;
|
||||
if (port >= 0)
|
||||
vty_out(vty, "%smgw remote-port %u%s", indent,
|
||||
vty_out(vty, "%s%sremote-port %u%s", indent, mgw_prefix,
|
||||
(uint16_t)port, VTY_NEWLINE);
|
||||
|
||||
if (conf->endpoint_domain_name[0])
|
||||
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
|
||||
vty_out(vty, "%s%sendpoint-domain %s%s", indent, mgw_prefix,
|
||||
conf->endpoint_domain_name, VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
|
||||
vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
|
||||
vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
|
||||
|
||||
if (conf->keepalive.req_interval_sec != 0)
|
||||
vty_out(vty, "%s%skeepalive request-interval %u%s", indent, mgw_prefix,
|
||||
conf->keepalive.req_interval_sec, VTY_NEWLINE);
|
||||
if (strncmp(conf->keepalive.req_endpoint_name, MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP,
|
||||
sizeof(conf->keepalive.req_endpoint_name)) != 0)
|
||||
vty_out(vty, "%s%skeepalive request-endpoint %s%s", indent, mgw_prefix,
|
||||
conf->keepalive.req_endpoint_name, VTY_NEWLINE);
|
||||
if (conf->keepalive.timeout_sec != 0)
|
||||
vty_out(vty, "%s%skeepalive timeout %u%s", indent, mgw_prefix,
|
||||
conf->keepalive.timeout_sec, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -279,6 +447,11 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
|
|||
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
|
||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
/* If caller supports MGW pool API (mgcp_client_pool_vty_init was
|
||||
* called), then skip printing any config in this node and print it when
|
||||
* the whole 'mgw' node is printed. */
|
||||
if (global_mgcp_client_pool)
|
||||
return CMD_SUCCESS;
|
||||
return config_write(vty, indent, global_mgcp_client_conf);
|
||||
}
|
||||
|
||||
|
@ -286,15 +459,18 @@ static void vty_init_common(void *talloc_ctx, int node)
|
|||
{
|
||||
global_mgcp_client_ctx = talloc_ctx;
|
||||
|
||||
install_lib_element(node, &cfg_mgw_local_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_local_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_remote_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_remote_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
|
||||
install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
|
||||
/* deprecated 'mgw' commands ('mgw' prepended as first arg) */
|
||||
install_lib_element(node, &cfg_mgw_mgw_local_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_local_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_remote_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_remote_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_endpoint_range_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_keepalive_req_interval_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_keepalive_req_endpoint_cmd);
|
||||
install_lib_element(node, &cfg_mgw_mgw_keepalive_timeout_cmd);
|
||||
|
||||
osmo_fsm_vty_add_cmds();
|
||||
}
|
||||
|
@ -319,38 +495,62 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
|
|||
vty_init_common(talloc_ctx, node);
|
||||
}
|
||||
|
||||
static int config_write_pool(struct vty *vty)
|
||||
/* Mark whether user called mgcp_client_pool_config_write() and hence support new API */
|
||||
static bool mgcp_client_pool_config_write_called = false;
|
||||
|
||||
static int _mgcp_client_pool_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
struct mgcp_client_pool *pool = global_mgcp_client_pool;
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
|
||||
char *indent = talloc_zero_size(vty, indent_buf_len);
|
||||
unsigned int subindent_buf_len;
|
||||
char *subindent;
|
||||
|
||||
snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
|
||||
if (!indent)
|
||||
indent = pool->vty_indent ? : "";
|
||||
subindent_buf_len = strlen(indent) + 1 + 1;
|
||||
subindent = talloc_zero_size(vty, subindent_buf_len);
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
|
||||
config_write(vty, indent, &pool_member->conf);
|
||||
snprintf(subindent, subindent_buf_len, "%s ", indent);
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->member_list, list) {
|
||||
vty_out(vty, "%smgw %u%s", indent, pool_member->nr, VTY_NEWLINE);
|
||||
config_write(vty, subindent, &pool_member->conf);
|
||||
}
|
||||
|
||||
talloc_free(indent);
|
||||
/* MGW pool API is supported by user (global_mgcp_client_pool is set
|
||||
* because mgcp_client_pool_vty_init was called). If single MGW was
|
||||
* configured through old VTY and no mgw in the new MGW pool VTY is
|
||||
* replacing it, then output the single MGW converted to the new MGW
|
||||
* pool VTY. */
|
||||
if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
|
||||
vty_out(vty, "%smgw 0%s", indent, VTY_NEWLINE);
|
||||
config_write(vty, subindent, global_mgcp_client_conf);
|
||||
}
|
||||
|
||||
talloc_free(subindent);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Lookup the selected MGCP client config by its reference number */
|
||||
static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
|
||||
/* Deprecated, used for backward compatibility with older users which didn't call
|
||||
* mgcp_client_pool_config_write(): */
|
||||
static int config_write_pool(struct vty *vty)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
struct mgcp_client_pool_member *pool_member_tmp;
|
||||
if (mgcp_client_pool_config_write_called)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
|
||||
if (pool_member_tmp->nr == nr) {
|
||||
pool_member = pool_member_tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _mgcp_client_pool_config_write(vty, NULL);
|
||||
}
|
||||
|
||||
return pool_member;
|
||||
/*! Write out MGCP client config to VTY.
|
||||
* \param[in] vty VTY to which we should print.
|
||||
* \param[in] indent string used for indentation (e.g. " ").
|
||||
If NULL, indentation passed during mgcp_client_pool_vty_init() will be used.
|
||||
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
|
||||
int mgcp_client_pool_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
/* Tell internal node write function that the user supports calling proper API: */
|
||||
mgcp_client_pool_config_write_called = true;
|
||||
return _mgcp_client_pool_config_write(vty, indent);
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_mgw,
|
||||
|
@ -359,13 +559,10 @@ DEFUN_ATTR(cfg_mgw,
|
|||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
|
||||
if (!pool_member) {
|
||||
pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
|
||||
pool_member = mgcp_client_pool_member_alloc(global_mgcp_client_pool, nr);
|
||||
OSMO_ASSERT(pool_member);
|
||||
mgcp_client_conf_init(&pool_member->conf);
|
||||
pool_member->nr = nr;
|
||||
llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
|
||||
}
|
||||
|
||||
vty->index = &pool_member->conf;
|
||||
|
@ -382,7 +579,7 @@ DEFUN_ATTR(cfg_no_mgw,
|
|||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@ -395,12 +592,7 @@ DEFUN_ATTR(cfg_no_mgw,
|
|||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_del(&pool_member->list);
|
||||
if (pool_member->client) {
|
||||
mgcp_client_disconnect(pool_member->client);
|
||||
talloc_free(pool_member->client);
|
||||
}
|
||||
talloc_free(pool_member);
|
||||
mgcp_client_pool_member_free(pool_member);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -412,7 +604,7 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
|
|||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@ -425,32 +617,10 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
|
|||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* Get rid of a possibly existing old MGCP client instance first */
|
||||
if (pool_member->client) {
|
||||
mgcp_client_disconnect(pool_member->client);
|
||||
talloc_free(pool_member->client);
|
||||
}
|
||||
|
||||
/* Create a new MGCP client instance with the current config */
|
||||
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
|
||||
if (!pool_member->client) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
|
||||
mgcp_client_pool_member_name(pool_member));
|
||||
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
|
||||
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
|
||||
pool_member->client->pool = global_mgcp_client_pool;
|
||||
|
||||
/* Connect client */
|
||||
if (mgcp_client_connect(pool_member->client)) {
|
||||
if (mgcp_client_pool_member_reinit_client(pool_member) < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
|
||||
mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
|
||||
pool_member->conf.remote_port);
|
||||
talloc_free(pool_member->client);
|
||||
pool_member->client = NULL;
|
||||
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
|
||||
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@ -466,7 +636,7 @@ DEFUN_ATTR(mgw_block, mgw_block_cmd,
|
|||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@ -483,7 +653,7 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
|
|||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
|
@ -493,22 +663,27 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
|
||||
DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
|
||||
{
|
||||
vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
|
||||
if (llist_empty(&global_mgcp_client_pool->member_list) && global_mgcp_client_pool->mgcp_client_single) {
|
||||
vty_out(vty, "%% (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
} else if (llist_empty(&global_mgcp_client_pool->pool)) {
|
||||
} else if (llist_empty(&global_mgcp_client_pool->member_list)) {
|
||||
vty_out(vty, "%% (pool is empty)%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
|
||||
llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
|
||||
const struct mgcp_client *cli = pool_member->client;
|
||||
vty_out(vty, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
|
||||
vty_out(vty, "%% mgcp-client: %s%s", pool_member->client ? "connected" : "disconnected",
|
||||
vty_out(vty, "%% MGCP link: %s,%s%s",
|
||||
cli && cli->iofd ? "connected" : "disconnected",
|
||||
cli && cli->conn_up ?
|
||||
((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
|
||||
"DOWN",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, "%% service: %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
|
||||
vty_out(vty, "%% ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
|
||||
|
@ -520,7 +695,8 @@ DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information abo
|
|||
* (called once at startup by the application process).
|
||||
* \param[in] parent_node identifier of the parent node on which the mgw node appears.
|
||||
* \param[in] mgw_node identifier that should be used with the newly installed MGW node.
|
||||
* \param[in] indent indentation string to match the indentation in the VTY config
|
||||
* \param[in] indent indentation string to match the indentation in the VTY config.
|
||||
If NULL, it must be passed explicitly each time mgcp_client_pool_config_write() is called.
|
||||
* \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
|
||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
|
||||
{
|
||||
|
@ -528,11 +704,12 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
|
|||
OSMO_ASSERT(pool);
|
||||
|
||||
/* Never allow this function to be called twice on the same pool */
|
||||
OSMO_ASSERT(!pool->vty_indent);
|
||||
OSMO_ASSERT(!pool->vty_node);
|
||||
|
||||
pool->vty_indent = talloc_strdup(pool, indent);
|
||||
OSMO_ASSERT(pool->vty_indent);
|
||||
if (indent) {
|
||||
pool->vty_indent = talloc_strdup(pool, indent);
|
||||
OSMO_ASSERT(pool->vty_indent);
|
||||
}
|
||||
pool->vty_node = talloc_zero(pool, struct cmd_node);
|
||||
OSMO_ASSERT(pool->vty_node);
|
||||
pool->vty_node->node = mgw_node;
|
||||
|
@ -542,8 +719,19 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
|
|||
install_lib_element(parent_node, &cfg_mgw_cmd);
|
||||
install_lib_element(parent_node, &cfg_no_mgw_cmd);
|
||||
|
||||
/* Note: config_write_pool is deprecated and user is expected to
|
||||
* manually call mgcp_client_pool_config_write() when printing the VTY
|
||||
* config */
|
||||
install_node(pool->vty_node, config_write_pool);
|
||||
vty_init_common(pool, mgw_node);
|
||||
install_lib_element(mgw_node, &cfg_mgw_local_ip_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_local_port_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_remote_ip_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_remote_port_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_rtp_bts_base_port_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_endpoint_domain_name_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_reset_ep_name_cmd);
|
||||
install_lib_element(mgw_node, &cfg_mgw_no_reset_ep_name_cmd);
|
||||
|
||||
install_element(mgw_node, &cfg_description_cmd);
|
||||
|
||||
|
@ -551,7 +739,7 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
|
|||
install_lib_element(ENABLE_NODE, &mgw_block_cmd);
|
||||
install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
|
||||
|
||||
install_lib_element_ve(&mgw_snow_cmd);
|
||||
install_lib_element_ve(&mgw_show_cmd);
|
||||
|
||||
global_mgcp_client_pool = pool;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,6 @@ AM_CFLAGS = \
|
|||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -45,7 +39,6 @@ libosmo_mgcp_a_SOURCES = \
|
|||
mgcp_stat.c \
|
||||
mgcp_endp.c \
|
||||
mgcp_trunk.c \
|
||||
mgcp_ctrl.c \
|
||||
mgcp_ratectr.c \
|
||||
mgcp_e1.c \
|
||||
mgcp_iuup.c \
|
||||
|
|
|
@ -276,75 +276,6 @@ error:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the given codec is applicable on the specified endpoint
|
||||
* Helper function for mgcp_codec_decide() */
|
||||
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
/* A codec name must be set, if not, this might mean that the codec
|
||||
* (payload type) that was assigned is unknown to us so we must stop
|
||||
* here. */
|
||||
if (!strlen(codec->subtype_name))
|
||||
return false;
|
||||
|
||||
/* FIXME: implement meaningful checks to make sure that the given codec
|
||||
* is compatible with the given endpoint */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Decide for one suitable codec
|
||||
* \param[in] conn related rtp-connection.
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
struct mgcp_rtp_end *rtp;
|
||||
unsigned int i;
|
||||
struct mgcp_endpoint *endp;
|
||||
bool codec_assigned = false;
|
||||
|
||||
endp = conn->conn->endp;
|
||||
rtp = &conn->end;
|
||||
|
||||
/* This function works on the results the SDP/LCO parser has extracted
|
||||
* from the MGCP message. The goal is to select a suitable codec for
|
||||
* the given connection. When transcoding is available, the first codec
|
||||
* from the codec list is taken without further checking. When
|
||||
* transcoding is not available, then the choice must be made more
|
||||
* carefully. Each codec in the list is checked until one is found that
|
||||
* is rated compatible. The rating is done by the helper function
|
||||
* is_codec_compatible(), which does the actual checking. */
|
||||
for (i = 0; i < rtp->codecs_assigned; i++) {
|
||||
/* When no transcoding is available, avoid codecs that would
|
||||
* require transcoding. */
|
||||
if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
|
||||
rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
rtp->codec = &rtp->codecs[i];
|
||||
codec_assigned = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME: To the reviewes: This is problematic. I do not get why we
|
||||
* need to reset the packet_duration_ms depending on the codec
|
||||
* selection. I thought it were all 20ms? Is this to address some
|
||||
* cornercase. (This piece of code was in the code path before,
|
||||
* together with the note: "TODO/XXX: Store this per codec and derive
|
||||
* it on use" */
|
||||
if (codec_assigned) {
|
||||
if (rtp->maximum_packet_time >= 0
|
||||
&& rtp->maximum_packet_time * rtp->codec->frame_duration_den >
|
||||
rtp->codec->frame_duration_num * 1500)
|
||||
rtp->packet_duration_ms = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
|
||||
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
|
||||
* Media Type Registration":
|
||||
|
@ -364,10 +295,15 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
|
|||
return codec->param.amr_octet_aligned;
|
||||
}
|
||||
|
||||
/* Compare two codecs, all parameters must match up, except for the payload type
|
||||
* number. */
|
||||
/* Compare two codecs, all parameters must match up */
|
||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
|
||||
{
|
||||
/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
|
||||
* exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
|
||||
* payload type numbers. Also the audio_name is not checked since it is already parsed into subtype_name, rate,
|
||||
* and channels, which are checked. */
|
||||
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
|
||||
return false;
|
||||
if (codec_a->rate != codec_b->rate)
|
||||
return false;
|
||||
if (codec_a->channels != codec_b->channels)
|
||||
|
@ -376,61 +312,172 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
|
|||
return false;
|
||||
if (codec_a->frame_duration_den != codec_b->frame_duration_den)
|
||||
return false;
|
||||
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
|
||||
return false;
|
||||
|
||||
/* Note: AMR allows to set the RTP payload format to octet-aligned or bandwith-efficient (octet-aligned=0)
|
||||
* via SDP. This difference concerns payload format only, but not the actual codec. It is not a difference
|
||||
* within the meaning of this function. */
|
||||
/* AMR payload may be formatted in two different payload formats, it is still the same codec but since the
|
||||
* formatting of the payload is different, conversation is required, so we must treat it as a different
|
||||
* codec here. */
|
||||
if (strcmp(codec_a->subtype_name, "AMR") == 0) {
|
||||
if (mgcp_codec_amr_is_octet_aligned(codec_a) != mgcp_codec_amr_is_octet_aligned(codec_b))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Translate a given payload type number that belongs to the packet of a
|
||||
* source connection to the equivalent payload type number that matches the
|
||||
* configuration of a destination connection.
|
||||
* \param[in] conn_src related source rtp-connection.
|
||||
* \param[in] conn_dst related destination rtp-connection.
|
||||
* \param[in] payload_type number from the source packet or source connection.
|
||||
* \returns translated payload type number on success, -EINVAL on failure. */
|
||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type)
|
||||
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
|
||||
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
|
||||
{
|
||||
struct mgcp_rtp_end *rtp_src;
|
||||
struct mgcp_rtp_end *rtp_dst;
|
||||
struct mgcp_rtp_codec *codec_src = NULL;
|
||||
struct mgcp_rtp_codec *codec_dst = NULL;
|
||||
/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
|
||||
* translate between different payload formats as long as the encoded voice data itself does not change.
|
||||
* Therefore we must insist on equal codecs but still allow different payload formatting. */
|
||||
|
||||
/* In 3G IuUP, AMR may be encapsulated in IuFP, this means even though the codec name and negotiated rate is
|
||||
* different, the formatting can still be converted by OsmoMGW. Therefore we won't insist on equal
|
||||
* subtype_name and rate if we detect IuFP and AMR is used on the same tandem. */
|
||||
if (strcmp(codec_a->subtype_name, "AMR") == 0 && strcmp(codec_b->subtype_name, "VND.3GPP.IUFP") == 0)
|
||||
goto iufp;
|
||||
if (strcmp(codec_a->subtype_name, "VND.3GPP.IUFP") == 0 && strcmp(codec_b->subtype_name, "AMR") == 0)
|
||||
goto iufp;
|
||||
|
||||
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
|
||||
return false;
|
||||
if (codec_a->rate != codec_b->rate)
|
||||
return false;
|
||||
iufp:
|
||||
if (codec_a->channels != codec_b->channels)
|
||||
return false;
|
||||
if (codec_a->frame_duration_num != codec_b->frame_duration_num)
|
||||
return false;
|
||||
if (codec_a->frame_duration_den != codec_b->frame_duration_den)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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 codecs_assigned;
|
||||
|
||||
rtp_src = &conn_src->end;
|
||||
rtp_dst = &conn_dst->end;
|
||||
rtp_end = &conn->end;
|
||||
|
||||
/* Find the codec information that is used on the source side */
|
||||
codecs_assigned = rtp_src->codecs_assigned;
|
||||
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
|
||||
* the first run we will look for an exact match. */
|
||||
codecs_assigned = rtp_end->codecs_assigned;
|
||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||
for (i = 0; i < codecs_assigned; i++) {
|
||||
if (payload_type == rtp_src->codecs[i].payload_type) {
|
||||
codec_src = &rtp_src->codecs[i];
|
||||
if (codecs_same(codec, &rtp_end->codecs[i])) {
|
||||
return &rtp_end->codecs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!codec_src)
|
||||
return -EINVAL;
|
||||
|
||||
/* Use the codec information from the source and try to find the
|
||||
* equivalent of it on the destination side */
|
||||
codecs_assigned = rtp_dst->codecs_assigned;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For a given codec, find a convertible codec in the given connection. */
|
||||
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
struct mgcp_rtp_end *rtp_end;
|
||||
unsigned int i;
|
||||
unsigned int codecs_assigned;
|
||||
struct mgcp_rtp_codec *codec_convertible = NULL;
|
||||
|
||||
rtp_end = &conn->end;
|
||||
|
||||
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
|
||||
* the first run we will look for an exact match. */
|
||||
codec_convertible = mgcp_codec_find_same(conn, codec);
|
||||
if (codec_convertible)
|
||||
return codec_convertible;
|
||||
|
||||
/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
|
||||
* payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
|
||||
codecs_assigned = rtp_end->codecs_assigned;
|
||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||
for (i = 0; i < codecs_assigned; i++) {
|
||||
if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
|
||||
codec_dst = &rtp_dst->codecs[i];
|
||||
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
|
||||
codec_convertible = &rtp_end->codecs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!codec_dst)
|
||||
|
||||
return codec_convertible;
|
||||
}
|
||||
|
||||
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
|
||||
* a tentative decision is made.
|
||||
* \param[inout] conn_src related rtp-connection.
|
||||
* \param[inout] conn_dst related destination rtp-connection (NULL if not present).
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* In case no destination connection is available (yet), or in case the destination connection exists but has
|
||||
* no codecs assigned, we are forced to make a simple tentative decision:
|
||||
* We just use the first codec of the source connection (conn_src) */
|
||||
OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
|
||||
if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
|
||||
if (conn_src->end.codecs_assigned >= 1) {
|
||||
conn_src->end.codec = &conn_src->end.codecs[0];
|
||||
return 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
|
||||
* of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
|
||||
* required. */
|
||||
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
|
||||
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
|
||||
struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src);
|
||||
if (codec_conn_dst) {
|
||||
/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
|
||||
* sides. We now set this codec on both connections. */
|
||||
conn_dst->end.codec = codec_conn_dst;
|
||||
conn_src->end.codec = codec_conn_src;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
|
||||
* to convert. */
|
||||
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
|
||||
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
|
||||
struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src);
|
||||
if (codec_conn_dst) {
|
||||
/* We found the a codec that we can convert to. Set each side to its codec. */
|
||||
conn_dst->end.codec = codec_conn_dst;
|
||||
conn_src->end.codec = codec_conn_src;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn_dst->end.codecs_assigned)
|
||||
conn_dst->end.codec = &conn_dst->end.codecs[0];
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return codec_dst->payload_type;
|
||||
if (conn_src->end.codecs_assigned)
|
||||
conn_src->end.codec = &conn_src->end.codecs[0];
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
|
||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
if (codec->param_present == false)
|
||||
return false;
|
||||
if (!codec->param.amr_octet_aligned_present)
|
||||
return false;
|
||||
if (strcmp(codec->subtype_name, "AMR") != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find the payload type number configured for a specific codec by SDP.
|
||||
|
@ -440,8 +487,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
|
|||
* \param subtype_name SDP codec name without parameters (e.g. "AMR").
|
||||
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
|
||||
* with incrementing match_nr.
|
||||
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found.
|
||||
*/
|
||||
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
|
||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
|
||||
const char *subtype_name, unsigned int match_nr)
|
||||
{
|
||||
|
@ -457,3 +503,26 @@ const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Lookup a codec that is assigned to a connection by its payload type number.
|
||||
* \param[in] conn related rtp-connection.
|
||||
* \param[in] payload_type number of the codec to look up.
|
||||
* \returns pointer to codec struct on success, NULL on failure. */
|
||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
|
||||
{
|
||||
struct mgcp_rtp_end *rtp_end = &conn->end;
|
||||
unsigned int codecs_assigned = rtp_end->codecs_assigned;
|
||||
struct mgcp_rtp_codec *codec = NULL;
|
||||
size_t i;
|
||||
|
||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||
|
||||
for (i = 0; i < codecs_assigned; i++) {
|
||||
if (payload_type == rtp_end->codecs[i].payload_type) {
|
||||
codec = &rtp_end->codecs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <osmocom/core/timer.h>
|
||||
#include <ctype.h>
|
||||
|
||||
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc rate_ctr_group_desc = {
|
||||
.group_name_prefix = "conn_rtp",
|
||||
.group_description = "rtp connection statistics",
|
||||
.class_id = 1,
|
||||
|
@ -95,17 +95,21 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
|
|||
static atomic_uint rate_ctr_index = 0;
|
||||
|
||||
conn_rtp->type = MGCP_RTP_DEFAULT;
|
||||
conn_rtp->osmux.cid_allocated = false;
|
||||
conn_rtp->osmux.cid = 0;
|
||||
|
||||
/* Osmux specific defaults, only used if conn is later on Osmux-enabled: */
|
||||
conn_rtp->osmux.state = OSMUX_STATE_DISABLED;
|
||||
conn_rtp->osmux.local_cid_allocated = false;
|
||||
conn_rtp->osmux.local_cid = 0;
|
||||
conn_rtp->osmux.remote_cid_present = false;
|
||||
conn_rtp->osmux.remote_cid = 0;
|
||||
|
||||
/* backpointer to the generic part of the connection */
|
||||
conn->u.rtp.conn = conn;
|
||||
|
||||
end->rtp.fd = -1;
|
||||
end->rtcp.fd = -1;
|
||||
end->rtp_port = end->rtcp_port = 0;
|
||||
talloc_free(end->fmtp_extra);
|
||||
end->fmtp_extra = NULL;
|
||||
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 */
|
||||
|
@ -113,12 +117,12 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
|
|||
end->output_enabled = false;
|
||||
end->maximum_packet_time = -1;
|
||||
|
||||
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
|
||||
if (!conn_rtp->rate_ctr_group)
|
||||
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
|
||||
if (!conn_rtp->ctrg)
|
||||
return -1;
|
||||
|
||||
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
|
||||
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_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);
|
||||
|
||||
/* Make sure codec table is reset */
|
||||
mgcp_codec_reset_all(conn_rtp);
|
||||
|
@ -134,7 +138,7 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
|
|||
if (mgcp_conn_rtp_is_iuup(conn_rtp))
|
||||
mgcp_conn_iuup_cleanup(conn_rtp);
|
||||
mgcp_free_rtp_port(&conn_rtp->end);
|
||||
rate_ctr_group_free(conn_rtp->rate_ctr_group);
|
||||
rate_ctr_group_free(conn_rtp->ctrg);
|
||||
mgcp_codec_reset_all(conn_rtp);
|
||||
}
|
||||
|
||||
|
@ -167,8 +171,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
|||
struct mgcp_conn *conn;
|
||||
int rc;
|
||||
|
||||
/* Do not allow more then two connections */
|
||||
if (llist_count(&endp->conns) >= endp->type->max_conns)
|
||||
/* Do not allow more than the maximum number of connections */
|
||||
if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns)
|
||||
return NULL;
|
||||
|
||||
/* Create new connection and add it to the list */
|
||||
|
@ -263,7 +267,7 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
|
|||
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 *conn_stats = conn_rtp->rate_ctr_group;
|
||||
struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
|
||||
|
||||
if (all_stats == NULL || conn_stats == NULL)
|
||||
return;
|
||||
|
@ -352,29 +356,37 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
|
|||
{
|
||||
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
|
||||
|
||||
if (!conn) {
|
||||
snprintf(str, sizeof(str), "(null connection)");
|
||||
return str;
|
||||
}
|
||||
if (!conn)
|
||||
return "NULL";
|
||||
|
||||
switch (conn->type) {
|
||||
case MGCP_CONN_TYPE_RTP:
|
||||
/* Dump RTP connection */
|
||||
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
|
||||
"rtp:%u rtcp:%u)",
|
||||
conn->name,
|
||||
conn->id,
|
||||
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
|
||||
ntohs(conn->u.rtp.end.rtp_port),
|
||||
ntohs(conn->u.rtp.end.rtcp_port));
|
||||
OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
|
||||
conn->name,
|
||||
mgcp_conn_rtp_type_name(conn->type),
|
||||
conn->id,
|
||||
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf) ? : "NULL",
|
||||
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
|
||||
conn->u.rtp.end.local_addr ? : "NULL",
|
||||
conn->u.rtp.end.local_port);
|
||||
|
||||
switch (conn->u.rtp.type) {
|
||||
case MGCP_RTP_OSMUX:
|
||||
OSMO_STRBUF_PRINTF(sb, " CID=%u", conn->u.rtp.osmux.local_cid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
OSMO_STRBUF_PRINTF(sb, ")");
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not happen, we should be able to dump
|
||||
* every possible connection type. */
|
||||
snprintf(str, sizeof(str), "(unknown connection type)");
|
||||
break;
|
||||
return "(unknown connection type)";
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -411,3 +423,10 @@ struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
|
|||
|
||||
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
||||
}
|
||||
|
||||
const struct value_string mgcp_conn_rtp_type_names[] = {
|
||||
{ MGCP_RTP_DEFAULT, "rtp" },
|
||||
{ MGCP_RTP_OSMUX, "osmux" },
|
||||
{ MGCP_RTP_IUUP, "iuup" },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
|
||||
* 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 <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
|
||||
|
||||
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
||||
void **node_data, int *i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
|
||||
const char *bind_addr, uint16_t port)
|
||||
{
|
||||
return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
|
||||
_LAST_CTRL_NODE);
|
||||
}
|
|
@ -222,7 +222,7 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
|
|||
osmo_i460_mux_enqueue(endp->e1.schan, msg);
|
||||
}
|
||||
|
||||
/* called by I.460 de-multeiplexer; 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 */
|
||||
static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
|
||||
unsigned int num_bits)
|
||||
{
|
||||
|
@ -301,7 +301,6 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
|
|||
|
||||
mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
|
||||
|
||||
msgb_free(msg);
|
||||
return;
|
||||
skip:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
|
||||
|
@ -309,8 +308,8 @@ skip:
|
|||
return;
|
||||
}
|
||||
|
||||
/* Function to handle outgoing E1 traffic */
|
||||
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
|
||||
/* handle outgoing E1 traffic */
|
||||
static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
|
||||
uint8_t *ptr;
|
||||
|
@ -359,19 +358,17 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
|
|||
osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
|
||||
|
||||
/* Trigger sending of pending E1 traffic */
|
||||
e1_send(ts, trunk);
|
||||
e1_send_ts_frame(ts, trunk);
|
||||
|
||||
/* e1inp_rx_ts() does not free() msgb */
|
||||
/* e1inp_rx_ts(), the caller of this callback does not free() msgb. */
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
||||
static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
||||
{
|
||||
/*! Each timeslot needs only to be configured once. The Timeslot then
|
||||
* stays open and permanently receives data. It is then up to the
|
||||
* I.460 demultiplexer to add/remove subchannels as needed. It is
|
||||
* allowed to call this function multiple times since we check if the
|
||||
* timeslot is already configured. */
|
||||
/*! One E1 timeslot may serve multiple I.460 subslots. The timeslot is opened as soon as an I.460 subslot is
|
||||
* opened and will stay open until the last I.460 subslot is closed (see e1_close below). This function must
|
||||
* be called any time a new I.460 subslot is opened in order to maintain constancy of the ts_usecount counter. */
|
||||
|
||||
struct e1inp_line *e1_line;
|
||||
int rc;
|
||||
|
@ -379,12 +376,14 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
|||
OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
|
||||
cfg = trunk->cfg;
|
||||
|
||||
if (trunk->e1.ts_in_use[ts_nr - 1]) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
|
||||
if (trunk->e1.ts_usecount[ts_nr - 1] > 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up and in use by %u subslot(s), using it as it is...\n",
|
||||
ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
|
||||
trunk->e1.ts_usecount[ts_nr - 1]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get E1 line */
|
||||
/* Find E1 line */
|
||||
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
|
||||
if (!e1_line) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
|
||||
|
@ -401,12 +400,61 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
|||
}
|
||||
rc = e1inp_line_update(e1_line);
|
||||
if (rc < 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", ts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
|
||||
trunk->e1.ts_in_use[ts_nr - 1] = true;
|
||||
trunk->e1.ts_usecount[ts_nr - 1]++;
|
||||
OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e1_close(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
||||
{
|
||||
/* See also comment above (e1_open). This function must be called any time an I.460 subslot is closed */
|
||||
|
||||
struct e1inp_line *e1_line;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
|
||||
cfg = trunk->cfg;
|
||||
|
||||
if (trunk->e1.ts_usecount[ts_nr - 1] > 1) {
|
||||
trunk->e1.ts_usecount[ts_nr - 1]--;
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u still in use by %u other subslot(s), leaving it open...\n",
|
||||
ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
|
||||
return 0;
|
||||
} else if (trunk->e1.ts_usecount[ts_nr - 1] == 0) {
|
||||
/* This should not be as it means we close the timeslot too often. */
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "E1 timeslot %u already closed, leaving it as it is...\n", ts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Find E1 line */
|
||||
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
|
||||
if (!e1_line) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
|
||||
trunk->e1.vty_line_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Release E1 timeslot */
|
||||
rc = e1inp_ts_config_none(&e1_line->ts[ts_nr - 1], e1_line);
|
||||
if (rc < 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to disable E1 timeslot %u.\n", ts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = e1inp_line_update(e1_line);
|
||||
if (rc < 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", trunk->e1.vty_line_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u closed.\n", ts_nr);
|
||||
trunk->e1.ts_usecount[ts_nr - 1]--;
|
||||
OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -496,7 +544,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
|
|||
}
|
||||
}
|
||||
|
||||
/* !Equip E1 endpoint with I.460 mux resources.
|
||||
/*! Equip E1 endpoint with I.460 mux and E1 timeslot resources.
|
||||
* \param[in] endp endpoint to equip
|
||||
* \param[in] ts E1 timeslot number.
|
||||
* \param[in] ss E1 subslot number.
|
||||
|
@ -517,7 +565,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
|
|||
endp->e1.last_amr_ft = AMR_4_75;
|
||||
|
||||
/* Set up E1 line / timeslot */
|
||||
rc = e1_init(endp->trunk, ts);
|
||||
rc = e1_open(endp->trunk, ts);
|
||||
if (rc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -604,9 +652,15 @@ void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
|||
}
|
||||
|
||||
/*! Remove E1 resources from endpoint
|
||||
* \param[in] endp endpoint to release. */
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
|
||||
* \param[in] endp endpoint to release.
|
||||
* \param[in] ts E1 timeslot number. */
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
|
||||
{
|
||||
/* Guard against multiple calls. In case we don't see a subchannel anymore we can safely assume that all work
|
||||
* is done. */
|
||||
if (!(endp->e1.schan || endp->e1.trau_rtp_st || endp->e1.trau_sync_fi))
|
||||
return;
|
||||
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
|
||||
|
||||
if (endp->e1.schan)
|
||||
|
@ -615,8 +669,10 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
|
|||
talloc_free(endp->e1.trau_rtp_st);
|
||||
if (endp->e1.trau_sync_fi)
|
||||
osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
|
||||
memset(&endp->e1, 0, sizeof(endp->e1));
|
||||
|
||||
/* Close E1 timeslot */
|
||||
e1_close(endp->trunk, ts);
|
||||
}
|
||||
|
||||
/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
const struct mgcp_endpoint_typeset ep_typeset = {
|
||||
/* Specify endpoint properties for RTP endpoint */
|
||||
.rtp = {
|
||||
.max_conns = 2,
|
||||
.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
|
||||
.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
|
||||
},
|
||||
|
@ -110,36 +109,6 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
|
|||
return endp;
|
||||
}
|
||||
|
||||
/*! release endpoint, all open connections are closed.
|
||||
* \param[in] endp endpoint to release */
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
|
||||
|
||||
/* Normally this function should only be called when
|
||||
* all connections have been removed already. In case
|
||||
* that there are still connections open (e.g. when
|
||||
* RSIP is executed), free them all at once. */
|
||||
mgcp_conn_free_all(endp);
|
||||
|
||||
/* We must only decrement the stat item when the endpoint as actually
|
||||
* claimed. An endpoint is claimed when a call-id is set */
|
||||
if (endp->callid)
|
||||
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
|
||||
TRUNK_STAT_ENDPOINTS_USED), 1);
|
||||
|
||||
/* Reset endpoint parameters and states */
|
||||
talloc_free(endp->callid);
|
||||
endp->callid = NULL;
|
||||
talloc_free(endp->local_options.string);
|
||||
endp->local_options.string = NULL;
|
||||
talloc_free(endp->local_options.codec);
|
||||
endp->local_options.codec = NULL;
|
||||
|
||||
if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
|
||||
mgcp_e1_endp_release(endp);
|
||||
}
|
||||
|
||||
/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
|
||||
* "ds/e1-") and write the epname without the prefix back to the memory
|
||||
* pointed at by epname. (per trunk the prefix is the same for all endpoints,
|
||||
|
@ -187,7 +156,6 @@ static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Convert all characters in epname to lowercase and strip trunk prefix and
|
||||
* endpoint name suffix (domain name) from epname. The result is written to
|
||||
* to the memory pointed at by epname_stripped. The expected size of the
|
||||
|
@ -260,6 +228,17 @@ bool mgcp_endp_is_wildcarded(const char *epname)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*! Check if the given epname refers to a "null" endpoint.
|
||||
* \param[in] epname endpoint name to check
|
||||
* \returns true if epname refers to "null"" endpoint, else false. */
|
||||
bool mgcp_endp_is_null(const char *epname)
|
||||
{
|
||||
if (strncasecmp(epname, "null@", 5) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Find an endpoint by its name on a specified trunk.
|
||||
* \param[out] cause pointer to store cause code, can be NULL.
|
||||
* \param[in] epname endpoint name to lookup.
|
||||
|
@ -675,3 +654,36 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
|||
if (llist_empty(&endp->conns))
|
||||
mgcp_endp_release(endp);
|
||||
}
|
||||
|
||||
/*! release endpoint, all open connections are closed.
|
||||
* \param[in] endp endpoint to release */
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
|
||||
|
||||
/* Normally this function should only be called when
|
||||
* all connections have been removed already. In case
|
||||
* that there are still connections open (e.g. when
|
||||
* RSIP is executed), free them all at once. */
|
||||
mgcp_conn_free_all(endp);
|
||||
|
||||
/* We must only decrement the stat item when the endpoint as actually
|
||||
* claimed. An endpoint is claimed when a call-id is set */
|
||||
if (endp->callid)
|
||||
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
|
||||
TRUNK_STAT_ENDPOINTS_USED), 1);
|
||||
|
||||
/* Reset endpoint parameters and states */
|
||||
talloc_free(endp->callid);
|
||||
endp->callid = NULL;
|
||||
talloc_free(endp->local_options.string);
|
||||
endp->local_options.string = NULL;
|
||||
talloc_free(endp->local_options.codec);
|
||||
endp->local_options.codec = NULL;
|
||||
|
||||
if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
|
||||
uint8_t ts = e1_ts_nr_from_epname(endp->name);
|
||||
mgcp_e1_endp_release(endp, ts);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,11 @@ static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t f
|
|||
uint8_t rfci_cnt = 0;
|
||||
unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
|
||||
struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
|
||||
OSMO_ASSERT(irp);
|
||||
if (!irp) {
|
||||
/* No IuUP Initialization has occured on the IuUP side yet. Return error and drop the RTP data, until
|
||||
* the IuUP Initialization has configured the link. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: cache this somehow */
|
||||
for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
|
||||
|
@ -270,9 +274,9 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||
return ft;
|
||||
}
|
||||
msgb_pull_to_l3(msg);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
|
||||
|
||||
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
|
||||
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->cmr = 15; /* no change */
|
||||
amr_hdr->f = 0;
|
||||
|
@ -291,6 +295,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||
amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
|
||||
amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
|
||||
msgb_trim(msg, amr_length);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR BE: ft %d, len %zd\n", ft, amr_length);
|
||||
}
|
||||
rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
|
||||
*rtp_hdr = (struct rtp_hdr){
|
||||
|
@ -306,7 +311,6 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
|
|||
};
|
||||
|
||||
rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -342,8 +346,7 @@ static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osm
|
|||
return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
|
||||
case MGCP_RTP_DEFAULT:
|
||||
return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
|
||||
case MGCP_OSMUX_BSC:
|
||||
case MGCP_OSMUX_BSC_NAT:
|
||||
case MGCP_RTP_OSMUX:
|
||||
default:
|
||||
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
|
||||
"Forward of IuUP payload to RTP connection type %u not supported!\n",
|
||||
|
@ -465,7 +468,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
|
|||
struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
|
||||
int buflen = msgb_length(msg);
|
||||
char *dest_name;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(conn_src);
|
||||
OSMO_ASSERT(conn_dst);
|
||||
|
@ -490,7 +493,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
|
|||
"rtp_port:%u rtcp_port:%u\n",
|
||||
dest_name,
|
||||
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
|
||||
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
|
||||
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
@ -502,27 +505,25 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
|
|||
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
|
||||
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
|
||||
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
|
||||
rtp_state->alt_rtp_tx_sequence++;
|
||||
|
||||
LOGPENDP(endp, DRTP, LOGL_DEBUG,
|
||||
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
|
||||
dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
|
||||
ntohs(rtp_end->rtp_port), 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_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
|
||||
msg);
|
||||
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
|
||||
|
||||
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
|
||||
(char *)hdr, buflen);
|
||||
rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
|
||||
|
||||
if (len <= 0)
|
||||
return len;
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
|
||||
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
|
||||
rtp_state->alt_rtp_tx_sequence++;
|
||||
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
|
||||
|
||||
return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
|
||||
|
@ -618,9 +619,8 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
|
|||
force_output_enabled = true;
|
||||
/* Fill in the peer address so that we can send Init-ACK back: */
|
||||
prev_rem_addr = conn_rtp_src->end.addr;
|
||||
prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
|
||||
prev_rem_rtp_port = osmo_sockaddr_port(&conn_rtp_src->end.addr.u.sa);
|
||||
conn_rtp_src->end.addr = *mc->from_addr;
|
||||
conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
|
||||
}
|
||||
|
||||
rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
|
||||
|
@ -628,7 +628,7 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
|
|||
if (force_output_enabled) {
|
||||
conn_rtp_src->end.output_enabled = prev_output_enabled;
|
||||
conn_rtp_src->end.addr = prev_rem_addr;
|
||||
conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
|
||||
osmo_sockaddr_set_port(&conn_rtp_src->end.addr.u.sa, prev_rem_rtp_port);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -638,7 +638,7 @@ free_ret:
|
|||
}
|
||||
|
||||
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
|
||||
* peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
|
||||
* peer and send it down the IuUP layer towards the destination as IuUP/RTP. Takes ownership of 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;
|
||||
|
@ -670,7 +670,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
|
|||
"Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
|
||||
goto free_ret;
|
||||
}
|
||||
if (amr_hdr->ft >= AMR_FT_MAX) {
|
||||
if (!osmo_amr_ft_valid(amr_hdr->ft)) {
|
||||
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
|
||||
goto free_ret;
|
||||
}
|
||||
|
@ -678,19 +678,22 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
|
|||
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
|
||||
goto free_ret;
|
||||
}
|
||||
irp->u.data.fqc = amr_hdr->q;
|
||||
irp->u.data.fqc = amr_hdr->q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
|
||||
irp->u.data.rfci = rfci;
|
||||
msgb_pull(msg, 2);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR OA -> IuUP: ft %d -> rfci %d len %d\n",
|
||||
amr_hdr->ft, rfci, msgb_length(msg));
|
||||
} else {
|
||||
uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
|
||||
int8_t ft;
|
||||
uint8_t q;
|
||||
if (msgb_length(msg) < 2) {
|
||||
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
|
||||
"Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
|
||||
goto free_ret;
|
||||
}
|
||||
ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
|
||||
if (ft >= AMR_FT_MAX) {
|
||||
if (!osmo_amr_ft_valid(ft)) {
|
||||
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
|
||||
goto free_ret;
|
||||
}
|
||||
|
@ -698,7 +701,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
|
|||
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
|
||||
goto free_ret;
|
||||
}
|
||||
irp->u.data.fqc = ((amr_bwe_hdr[1] & 0x40) >> 6);
|
||||
q = amr_bwe_hdr[1] & 0x40;
|
||||
irp->u.data.fqc = q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
|
||||
irp->u.data.rfci = rfci;
|
||||
rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
|
||||
if (rc < 0) {
|
||||
|
@ -706,6 +710,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
|
|||
return rc;
|
||||
}
|
||||
msgb_trim(msg, iuup_length);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR BE -> IuUP: ft %d -> rfci %d len %d\n",
|
||||
ft, rfci, msgb_length(msg));
|
||||
}
|
||||
|
||||
irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
|
||||
|
|
|
@ -75,7 +75,7 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
|
|||
}
|
||||
|
||||
/*! Parse connection mode.
|
||||
* \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
|
||||
* \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
|
||||
* \param[in] endp pointer to endpoint (only used for log output)
|
||||
* \param[out] associated connection to be modified accordingly
|
||||
* \returns 0 on success, -1 on error */
|
||||
|
@ -100,6 +100,8 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
|
|||
conn->mode = MGCP_CONN_RECV_SEND;
|
||||
else if (strcasecmp(mode, "sendonly") == 0)
|
||||
conn->mode = MGCP_CONN_SEND_ONLY;
|
||||
else if (strcasecmp(mode, "confecho") == 0)
|
||||
conn->mode = MGCP_CONN_CONFECHO;
|
||||
else if (strcasecmp(mode, "loopback") == 0)
|
||||
conn->mode = MGCP_CONN_LOOPBACK;
|
||||
else {
|
||||
|
@ -202,7 +204,7 @@ int mgcp_parse_osmux_cid(const char *line)
|
|||
osmux_cid, OSMUX_CID_MAX);
|
||||
return -2;
|
||||
}
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
|
||||
|
||||
return osmux_cid;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -47,6 +47,7 @@
|
|||
#include <osmocom/mgcp/mgcp_codec.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_iuup.h>
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
|
||||
/* Contains the last successfully resolved endpoint name. This variable is used
|
||||
* for the unit-tests to verify that the endpoint was correctly resolved. */
|
||||
|
@ -85,6 +86,9 @@ struct mgcp_request_data {
|
|||
/* set to true when the request has been classified as wildcarded */
|
||||
bool wildcarded;
|
||||
|
||||
/* Set to true when the request is targeted at the "null" endpoint */
|
||||
bool null_endp;
|
||||
|
||||
/* contains cause code in case of problems during endp/trunk resolution */
|
||||
int mgcp_cause;
|
||||
};
|
||||
|
@ -150,8 +154,7 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
|
|||
|
||||
switch (conn->type) {
|
||||
case MGCP_RTP_DEFAULT:
|
||||
case MGCP_OSMUX_BSC:
|
||||
case MGCP_OSMUX_BSC_NAT:
|
||||
case MGCP_RTP_OSMUX:
|
||||
case MGCP_RTP_IUUP:
|
||||
break;
|
||||
default:
|
||||
|
@ -301,7 +304,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
|
|||
|
||||
/* Attach optional OSMUX parameters */
|
||||
if (mgcp_conn_rtp_is_osmux(conn)) {
|
||||
rc = msgb_printf(sdp, "X-Osmux: %u\r\n", conn->osmux.cid);
|
||||
rc = msgb_printf(sdp, MGCP_X_OSMO_OSMUX_HEADER " %u\r\n", conn->osmux.local_cid);
|
||||
if (rc < 0)
|
||||
goto error;
|
||||
}
|
||||
|
@ -324,8 +327,13 @@ error:
|
|||
* osmux connection, send the dummy packet via OSMUX */
|
||||
static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
if (conn->osmux.state != OSMUX_STATE_DISABLED)
|
||||
osmux_send_dummy(endp, conn);
|
||||
/* Avoid sending dummy packet if the remote address was not yet
|
||||
* configured through CRCX/MDCX: */
|
||||
if (!mgcp_rtp_end_remote_addr_available(&conn->end))
|
||||
return;
|
||||
|
||||
if (mgcp_conn_rtp_is_osmux(conn))
|
||||
osmux_send_dummy(conn);
|
||||
else
|
||||
mgcp_send_dummy(endp, conn);
|
||||
}
|
||||
|
@ -385,7 +393,10 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
|
|||
/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
|
||||
rq.pdata = &pdata;
|
||||
rq.wildcarded = mgcp_endp_is_wildcarded(pdata.epname);
|
||||
rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
|
||||
if (!rq.wildcarded)
|
||||
rq.null_endp = mgcp_endp_is_null(pdata.epname);
|
||||
if (!rq.null_endp)
|
||||
rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
|
||||
rq.mgcp_cause = rc;
|
||||
if (!rq.endp) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_NO_ENDPOINT));
|
||||
|
@ -402,14 +413,14 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
|
|||
rq.name, pdata.epname);
|
||||
return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
|
||||
}
|
||||
} else {
|
||||
} else if (!rq.null_endp) {
|
||||
/* If the endpoint name suggests that the request refers to a specific endpoint, then the
|
||||
* request cannot be handled and we must stop early. */
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
|
||||
pdata.epname, -rq.mgcp_cause);
|
||||
return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
|
||||
}
|
||||
} /* else: Handle special "null" endpoint below (with rq.endp=NULL, rq.trunk=NULL) */
|
||||
} else {
|
||||
osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
|
||||
rq.trunk = rq.endp->trunk;
|
||||
|
@ -455,6 +466,11 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
|
|||
static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
|
||||
{
|
||||
LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
|
||||
|
||||
/* Auditing "null" endpoint is allowed for keepalive purposes. There's no rq->endp nor rq->trunk in this case. */
|
||||
if (rq->null_endp)
|
||||
return create_ok_response(rq->pdata->cfg, NULL, 200, "AUEP", rq->pdata->trans);
|
||||
|
||||
if (!rq->endp || !mgcp_endp_avail(rq->endp)) {
|
||||
LOGPENDP(rq->endp, DLMGCP, LOGL_ERROR, "AUEP: selected endpoint not available!\n");
|
||||
return create_err_response(rq->trunk, NULL, 501, "AUEP", rq->pdata->trans);
|
||||
|
@ -656,8 +672,8 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
|
|||
case 'a':
|
||||
/* FIXME: LCO also supports the negotiation of more than one codec.
|
||||
* (e.g. a:PCMU;G726-32) But this implementation only supports a single
|
||||
* codec only. */
|
||||
if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
|
||||
* 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: */
|
||||
|
@ -709,7 +725,7 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
|||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
|
||||
"Configuring RTP endpoint: local port %d%s%s\n",
|
||||
ntohs(rtp->rtp_port),
|
||||
osmo_sockaddr_port(&rtp->addr.u.sa),
|
||||
rtp->force_aligned_timing ? ", force constant timing" : "",
|
||||
rtp->force_constant_ssrc ? ", force constant ssrc" : "");
|
||||
}
|
||||
|
@ -740,12 +756,12 @@ uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
|
|||
*/
|
||||
static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
|
||||
{
|
||||
if (!endp->trunk->cfg->osmux_init) {
|
||||
if (osmux_init(OSMUX_ROLE_BSC, endp->trunk->cfg) < 0) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
|
||||
if (!endp->trunk->cfg->osmux.initialized) {
|
||||
if (osmux_init(endp->trunk) < 0) {
|
||||
LOGPENDP(endp, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
|
||||
return -3;
|
||||
}
|
||||
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
|
||||
LOGPENDP(endp, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
|
||||
}
|
||||
|
||||
return mgcp_parse_osmux_cid(line);
|
||||
|
@ -756,6 +772,9 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
|
|||
struct mgcp_request_data *rq, int have_sdp, bool crcx)
|
||||
{
|
||||
struct mgcp_endpoint *endp = rq->endp;
|
||||
struct mgcp_conn *conn_dst;
|
||||
struct mgcp_conn_rtp *conn_dst_rtp;
|
||||
|
||||
int rc;
|
||||
char *cmd;
|
||||
|
||||
|
@ -797,8 +816,15 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* Try to find an destination RTP connection that we can include in the codec decision. */
|
||||
conn_dst = mgcp_find_dst_conn(conn->conn);
|
||||
if (conn_dst && conn_dst->type == MGCP_CONN_TYPE_RTP)
|
||||
conn_dst_rtp = &conn_dst->u.rtp;
|
||||
else
|
||||
conn_dst_rtp = NULL;
|
||||
|
||||
/* Make codec decision */
|
||||
if (mgcp_codec_decide(conn) != 0)
|
||||
if (mgcp_codec_decide(conn, conn_dst_rtp) != 0)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
@ -840,13 +866,13 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
|
|||
struct mgcp_parse_data *pdata = rq->pdata;
|
||||
struct mgcp_trunk *trunk = rq->trunk;
|
||||
struct mgcp_endpoint *endp = rq->endp;
|
||||
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
|
||||
struct rate_ctr_group *rate_ctrs;
|
||||
int error_code = 400;
|
||||
const char *local_options = NULL;
|
||||
const char *callid = NULL;
|
||||
const char *mode = NULL;
|
||||
char *line;
|
||||
int have_sdp = 0, osmux_cid = -2;
|
||||
int have_sdp = 0, remote_osmux_cid = -2;
|
||||
struct mgcp_conn_rtp *conn = NULL;
|
||||
struct mgcp_conn *_conn = NULL;
|
||||
char conn_name[512];
|
||||
|
@ -854,6 +880,14 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
|
|||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
|
||||
|
||||
if (rq->null_endp) {
|
||||
/* trunk not available so rate_ctr aren't available either. */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "CRCX: Not allowed in 'null' endpoint!\n");
|
||||
return create_err_response(pdata->cfg, NULL, 502, "CRCX", pdata->trans);
|
||||
}
|
||||
|
||||
rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
|
||||
|
||||
/* we must have a free ep */
|
||||
if (!endp) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
|
||||
|
@ -893,9 +927,9 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
|
|||
case 'X':
|
||||
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
|
||||
/* If osmux is disabled, just skip setting it up */
|
||||
if (!rq->endp->trunk->cfg->osmux)
|
||||
if (rq->endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
|
||||
break;
|
||||
osmux_cid = mgcp_osmux_setup(endp, line);
|
||||
remote_osmux_cid = mgcp_osmux_setup(endp, line);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -933,7 +967,7 @@ mgcp_header_done:
|
|||
}
|
||||
|
||||
/* Check if we are able to accept the creation of another connection */
|
||||
if (llist_count(&endp->conns) >= endp->type->max_conns) {
|
||||
if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"CRCX: endpoint full, max. %i connections allowed!\n",
|
||||
endp->type->max_conns);
|
||||
|
@ -998,16 +1032,17 @@ mgcp_header_done:
|
|||
goto error2;
|
||||
}
|
||||
|
||||
/* Annotate Osmux circuit ID and set it to negotiating state until this
|
||||
* is fully set up from the dummy load. */
|
||||
conn->osmux.state = OSMUX_STATE_DISABLED;
|
||||
if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
|
||||
conn->osmux.state = OSMUX_STATE_ACTIVATING;
|
||||
if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
|
||||
/* If X-Osmux (remote CID) was received (-1 is wilcard), alloc next avail CID as local CID */
|
||||
if (remote_osmux_cid >= -1) {
|
||||
if (osmux_init_conn(conn) < 0) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
|
||||
goto error2;
|
||||
}
|
||||
} else if (endp->trunk->cfg->osmux == OSMUX_USAGE_ONLY) {
|
||||
if (remote_osmux_cid >= 0) {
|
||||
conn->osmux.remote_cid_present = true;
|
||||
conn->osmux.remote_cid = remote_osmux_cid;
|
||||
}
|
||||
} else if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_ONLY) {
|
||||
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
|
||||
"CRCX: osmux only and no osmux offered\n");
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
|
||||
|
@ -1020,7 +1055,7 @@ mgcp_header_done:
|
|||
&endp->local_options, local_options);
|
||||
if (rc != 0) {
|
||||
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
|
||||
"CRCX: inavlid local connection options!\n");
|
||||
"CRCX: invalid local connection options!\n");
|
||||
error_code = rc;
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
|
||||
goto error2;
|
||||
|
@ -1041,9 +1076,6 @@ mgcp_header_done:
|
|||
rc = mgcp_conn_iuup_init(conn);
|
||||
}
|
||||
|
||||
conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
|
||||
trunk->audio_fmtp_extra);
|
||||
|
||||
if (pdata->cfg->force_ptime) {
|
||||
conn->end.packet_duration_ms = pdata->cfg->force_ptime;
|
||||
conn->end.force_output_ptime = 1;
|
||||
|
@ -1054,7 +1086,7 @@ mgcp_header_done:
|
|||
/* check connection mode setting */
|
||||
if (conn->conn->mode != MGCP_CONN_LOOPBACK
|
||||
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
|
||||
&& conn->end.rtp_port == 0) {
|
||||
&& osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
|
||||
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
|
||||
"CRCX: selected connection mode type requires an opposite end!\n");
|
||||
error_code = 527;
|
||||
|
@ -1064,7 +1096,10 @@ mgcp_header_done:
|
|||
|
||||
/* Find a local address for conn based on policy and initial SDP remote
|
||||
information, then find a free port for it */
|
||||
mgcp_get_local_addr(conn->end.local_addr, conn);
|
||||
if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
|
||||
goto error2;
|
||||
}
|
||||
if (allocate_port(endp, conn) != 0) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
|
||||
goto error2;
|
||||
|
@ -1077,13 +1112,20 @@ mgcp_header_done:
|
|||
goto error2;
|
||||
}
|
||||
|
||||
/* Notify Osmux conn that CRCX was received */
|
||||
if (mgcp_conn_rtp_is_osmux(conn)) {
|
||||
if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
|
||||
"CRCX: Creating connection: port: %u\n", conn->end.local_port);
|
||||
|
||||
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
|
||||
OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
|
||||
if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
|
||||
mgcp_rtp_end_remote_addr_available(&conn->end) &&
|
||||
trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
|
||||
send_dummy(endp, conn);
|
||||
|
||||
|
@ -1108,7 +1150,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
|
|||
struct mgcp_parse_data *pdata = rq->pdata;
|
||||
struct mgcp_trunk *trunk = rq->trunk;
|
||||
struct mgcp_endpoint *endp = rq->endp;
|
||||
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
|
||||
struct rate_ctr_group *rate_ctrs;
|
||||
char new_local_addr[INET6_ADDRSTRLEN];
|
||||
int error_code = 500;
|
||||
int silent = 0;
|
||||
|
@ -1118,11 +1160,19 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
|
|||
const char *mode = NULL;
|
||||
struct mgcp_conn_rtp *conn = NULL;
|
||||
const char *conn_id = NULL;
|
||||
int osmux_cid = -2;
|
||||
int remote_osmux_cid = -2;
|
||||
int rc;
|
||||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
|
||||
|
||||
if (rq->null_endp) {
|
||||
/* trunk not available so rate_ctr aren't available either. */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MDCX: Not allowed in 'null' endpoint!\n");
|
||||
return create_err_response(pdata->cfg, NULL, 502, "MDCX", pdata->trans);
|
||||
}
|
||||
|
||||
rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
|
||||
|
||||
/* Prohibit wildcarded requests */
|
||||
if (rq->wildcarded) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
|
@ -1174,9 +1224,9 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
|
|||
case 'X':
|
||||
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
|
||||
/* If osmux is disabled, just skip setting it up */
|
||||
if (!endp->trunk->cfg->osmux)
|
||||
if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
|
||||
break;
|
||||
osmux_cid = mgcp_osmux_setup(endp, line);
|
||||
remote_osmux_cid = mgcp_osmux_setup(endp, line);
|
||||
break;
|
||||
}
|
||||
/* Ignore unknown X-headers */
|
||||
|
@ -1240,6 +1290,10 @@ mgcp_header_done:
|
|||
error_code = rc;
|
||||
goto error3;
|
||||
}
|
||||
/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
|
||||
/* TODO: "codec" probably needs to be moved from endp to conn */
|
||||
if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0)
|
||||
rc = mgcp_conn_iuup_init(conn);
|
||||
|
||||
/* check connection mode setting */
|
||||
if (conn->conn->mode != MGCP_CONN_LOOPBACK
|
||||
|
@ -1253,30 +1307,39 @@ mgcp_header_done:
|
|||
}
|
||||
|
||||
if (mgcp_conn_rtp_is_osmux(conn)) {
|
||||
OSMO_ASSERT(conn->osmux.cid_allocated);
|
||||
if (osmux_cid < -1) {
|
||||
OSMO_ASSERT(conn->osmux.local_cid_allocated);
|
||||
if (remote_osmux_cid < -1) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"MDCX: Failed to parse Osmux CID!\n");
|
||||
goto error3;
|
||||
} else if (osmux_cid == -1) {
|
||||
} else if (remote_osmux_cid == -1) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"MDCX: wilcard in MDCX is not supported!\n");
|
||||
goto error3;
|
||||
} else if (osmux_cid != (int) conn->osmux.cid) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"MDCX: changing already allocated CID is not supported!\n");
|
||||
goto error3;
|
||||
} else if (conn->osmux.remote_cid_present &&
|
||||
remote_osmux_cid != conn->osmux.remote_cid) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"MDCX: changing already allocated CID is not supported!\n");
|
||||
goto error3;
|
||||
} else {
|
||||
conn->osmux.remote_cid_present = true;
|
||||
conn->osmux.remote_cid = remote_osmux_cid;
|
||||
if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"MDCX: Osmux handling failed!\n");
|
||||
goto error3;
|
||||
}
|
||||
}
|
||||
/* TODO: In the future (when we have recvCID!=sendCID), we need to
|
||||
tell Osmux code that osmux_cid is to be used as sendCID for
|
||||
that conn. */
|
||||
}
|
||||
|
||||
/* MDCX 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. */
|
||||
mgcp_get_local_addr(new_local_addr, conn);
|
||||
if (mgcp_get_local_addr(new_local_addr, conn) < 0) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
|
||||
goto error3;
|
||||
}
|
||||
if (strcmp(new_local_addr, conn->end.local_addr)) {
|
||||
osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
|
||||
mgcp_free_rtp_port(&conn->end);
|
||||
|
@ -1300,7 +1363,6 @@ mgcp_header_done:
|
|||
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
|
||||
OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
|
||||
if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
|
||||
mgcp_rtp_end_remote_addr_available(&conn->end) &&
|
||||
trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
|
||||
send_dummy(endp, conn);
|
||||
|
||||
|
@ -1326,7 +1388,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
|
|||
struct mgcp_parse_data *pdata = rq->pdata;
|
||||
struct mgcp_trunk *trunk = rq->trunk;
|
||||
struct mgcp_endpoint *endp = rq->endp;
|
||||
struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
|
||||
struct rate_ctr_group *rate_ctrs;
|
||||
int error_code = 400;
|
||||
int silent = 0;
|
||||
char *line;
|
||||
|
@ -1336,10 +1398,18 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
|
|||
unsigned int i;
|
||||
|
||||
/* NOTE: In this handler we can not take it for granted that the endp
|
||||
* pointer will be populated, however a trunk is always guaranteed. */
|
||||
* pointer will be populated, however a trunk is always guaranteed (except for 'null' endp).
|
||||
*/
|
||||
|
||||
LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: deleting connection(s) ...\n");
|
||||
|
||||
if (rq->null_endp) {
|
||||
/* trunk not available so rate_ctr aren't available either. */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "DLCX: Not allowed in 'null' endpoint!\n");
|
||||
return create_err_response(pdata->cfg, NULL, 502, "DLCX", pdata->trans);
|
||||
}
|
||||
|
||||
rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
|
||||
if (endp && !mgcp_endp_avail(endp)) {
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
|
@ -1490,6 +1560,12 @@ static struct msgb *handle_rsip(struct mgcp_request_data *rq)
|
|||
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
|
||||
|
||||
if (rq->null_endp) {
|
||||
/* trunk not available so rate_ctr aren't available either. */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "RSIP: Not allowed in 'null' endpoint!\n");
|
||||
return create_err_response(rq->pdata->cfg, NULL, 502, "RSIP", rq->pdata->trans);
|
||||
}
|
||||
|
||||
if (rq->pdata->cfg->reset_cb)
|
||||
rq->pdata->cfg->reset_cb(rq->endp->trunk);
|
||||
return NULL;
|
||||
|
@ -1515,6 +1591,12 @@ static struct msgb *handle_noti_req(struct mgcp_request_data *rq)
|
|||
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
|
||||
|
||||
if (rq->null_endp) {
|
||||
/* trunk not available so rate_ctr aren't available either. */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "RQNT: Not allowed in 'null' endpoint!\n");
|
||||
return create_err_response(rq->pdata->cfg, NULL, 502, "RQNT", rq->pdata->trans);
|
||||
}
|
||||
|
||||
for_each_line(line, rq->pdata->save) {
|
||||
switch (toupper(line[0])) {
|
||||
case 'S':
|
||||
|
@ -1569,8 +1651,7 @@ static void mgcp_keepalive_timer_cb(void *_trunk)
|
|||
struct mgcp_endpoint *endp = trunk->endpoints[i];
|
||||
llist_for_each_entry(conn, &endp->conns, entry) {
|
||||
if (conn->type == MGCP_CONN_TYPE_RTP &&
|
||||
conn->mode == MGCP_CONN_RECV_ONLY &&
|
||||
mgcp_rtp_end_remote_addr_available(&conn->u.rtp.end))
|
||||
conn->mode == MGCP_CONN_RECV_ONLY)
|
||||
send_dummy(endp, &conn->u.rtp);
|
||||
}
|
||||
}
|
||||
|
@ -1624,13 +1705,10 @@ struct mgcp_config *mgcp_config_alloc(void)
|
|||
|
||||
cfg->source_port = 2427;
|
||||
osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
|
||||
osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr));
|
||||
|
||||
cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
|
||||
cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
|
||||
|
||||
cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
|
||||
|
||||
INIT_LLIST_HEAD(&cfg->trunks);
|
||||
|
||||
/* Allocate virtual trunk */
|
||||
|
|
|
@ -43,7 +43,7 @@ static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
|
|||
{ "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
|
||||
.group_name_prefix = "mgcp",
|
||||
.group_description = "mgcp general statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -71,7 +71,7 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
|
|||
[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
|
||||
.group_name_prefix = "crcx",
|
||||
.group_description = "crxc statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -97,7 +97,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
|
|||
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
|
||||
.group_name_prefix = "mdcx",
|
||||
.group_description = "mdcx statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -116,7 +116,7 @@ static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
|
|||
[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
|
||||
.group_name_prefix = "dlcx",
|
||||
.group_description = "dlcx statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -130,7 +130,7 @@ static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
|
|||
[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
|
||||
.group_name_prefix = "e1",
|
||||
.group_description = "e1 statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
|
@ -138,7 +138,7 @@ const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
|
|||
.ctr_desc = e1_rate_ctr_desc
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
|
||||
static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
|
||||
.group_name_prefix = "all_rtp_conn",
|
||||
.group_description = "aggregated statistics for all rtp connections",
|
||||
.class_id = 1,
|
||||
|
@ -146,6 +146,14 @@ const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
|
|||
.ctr_desc = all_rtp_conn_rate_ctr_desc
|
||||
};
|
||||
|
||||
static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
|
||||
.group_name_prefix = "all_osmux_conn",
|
||||
.group_description = "aggregated statistics for all osmux connections",
|
||||
.class_id = 1,
|
||||
.num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
|
||||
.ctr_desc = all_osmux_conn_rate_ctr_desc
|
||||
};
|
||||
|
||||
/*! allocate global rate counters
|
||||
* (called once at startup).
|
||||
* \param[in] cfg mgw configuration for which the rate counters are allocated.
|
||||
|
@ -191,6 +199,7 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
|
|||
static atomic_uint mdcx_rate_ctr_index = 0;
|
||||
static atomic_uint dlcx_rate_ctr_index = 0;
|
||||
static atomic_uint all_rtp_conn_rate_ctr_index = 0;
|
||||
static atomic_uint all_osmux_conn_rate_ctr_index = 0;
|
||||
char ctr_name[256];
|
||||
|
||||
if (ratectr->mgcp_crcx_ctr_group == NULL) {
|
||||
|
@ -229,6 +238,15 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
|
|||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
|
||||
}
|
||||
if (ratectr->all_osmux_conn_stats == NULL) {
|
||||
ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
|
||||
all_osmux_conn_rate_ctr_index++);
|
||||
if (!ratectr->all_osmux_conn_stats)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
|
||||
}
|
||||
|
||||
/* E1 specific */
|
||||
if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
|
||||
|
@ -265,6 +283,10 @@ void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
|
|||
rate_ctr_group_free(ratectr->all_rtp_conn_stats);
|
||||
ratectr->all_rtp_conn_stats = NULL;
|
||||
}
|
||||
if (ratectr->all_osmux_conn_stats) {
|
||||
rate_ctr_group_free(ratectr->all_osmux_conn_stats);
|
||||
ratectr->all_osmux_conn_stats = NULL;
|
||||
}
|
||||
|
||||
/* E1 specific */
|
||||
if (ratectr->e1_stats) {
|
||||
|
|
|
@ -239,13 +239,12 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
|
|||
if (delimiter == ';' || delimiter == ',')
|
||||
str_ptr[strlen(str_ptr) - 1] = '\0';
|
||||
|
||||
/* AMR octet aligned parameter */
|
||||
/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
|
||||
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
|
||||
fmtp_param->param.amr_octet_aligned_present = true;
|
||||
fmtp_param->param.amr_octet_aligned = false;
|
||||
if (amr_octet_aligned == 1)
|
||||
fmtp_param->param.amr_octet_aligned = true;
|
||||
|
||||
}
|
||||
|
||||
param_str = strtok(NULL, " ");
|
||||
|
@ -384,7 +383,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
|||
case 'm':
|
||||
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
|
||||
if (rc == 1) {
|
||||
rtp->rtp_port = htons(port);
|
||||
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
|
||||
rtp->rtcp_port = htons(port + 1);
|
||||
}
|
||||
|
||||
|
@ -432,7 +431,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
|||
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
|
||||
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
|
||||
ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
|
||||
osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
|
||||
rtp->packet_duration_ms);
|
||||
if (codecs_used == 0)
|
||||
LOGPC(DLMGCP, LOGL_NOTICE, "none");
|
||||
|
@ -489,34 +488,10 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
|
|||
}
|
||||
|
||||
/* Add fmtp strings to sdp payload */
|
||||
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
|
||||
const char *fmtp_extra)
|
||||
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
|
||||
{
|
||||
unsigned int i;
|
||||
int rc;
|
||||
int fmtp_extra_pt = -1;
|
||||
char *fmtp_extra_pars = "";
|
||||
|
||||
/* When no fmtp parameters ara available but an fmtp extra string
|
||||
* is configured, just add the fmtp extra string */
|
||||
if (fmtp_params_len == 0 && fmtp_extra) {
|
||||
return msgb_printf(sdp, "%s\r\n", fmtp_extra);
|
||||
}
|
||||
|
||||
/* When there is fmtp extra configured we dissect it in order to drop
|
||||
* in the configured extra parameters at the right place when
|
||||
* generating the fmtp strings. */
|
||||
if (fmtp_extra) {
|
||||
if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
|
||||
fmtp_extra_pt = -1;
|
||||
|
||||
fmtp_extra_pars = strstr(fmtp_extra, " ");
|
||||
|
||||
if (!fmtp_extra_pars)
|
||||
fmtp_extra_pars = "";
|
||||
else
|
||||
fmtp_extra_pars++;
|
||||
}
|
||||
|
||||
for (i = 0; i < fmtp_params_len; i++) {
|
||||
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
|
||||
|
@ -533,13 +508,6 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Append extra parameters from fmtp extra */
|
||||
if (fmtp_params[i].payload_type == fmtp_extra_pt) {
|
||||
rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msgb_printf(sdp, "\r\n");
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
|
@ -559,7 +527,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||
const char *addr)
|
||||
{
|
||||
const struct mgcp_rtp_codec *codec;
|
||||
const char *fmtp_extra;
|
||||
const char *audio_name;
|
||||
int payload_type;
|
||||
struct sdp_fmtp_param fmtp_param;
|
||||
|
@ -575,10 +542,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||
OSMO_ASSERT(sdp);
|
||||
OSMO_ASSERT(addr);
|
||||
|
||||
/* 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);
|
||||
codec = conn->end.codec;
|
||||
|
||||
audio_name = codec->audio_name;
|
||||
payload_type = codec->payload_type;
|
||||
|
@ -601,7 +565,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||
|
||||
payload_types[0] = payload_type;
|
||||
if (mgcp_conn_rtp_is_osmux(conn))
|
||||
local_port = endp->trunk->cfg->osmux_port;
|
||||
local_port = endp->trunk->cfg->osmux.local_port;
|
||||
else
|
||||
local_port = conn->end.local_port;
|
||||
rc = add_audio(sdp, payload_types, 1, local_port);
|
||||
|
@ -620,7 +584,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
|||
fmtp_params[0] = fmtp_param;
|
||||
fmtp_params_len = 1;
|
||||
}
|
||||
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
|
||||
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len);
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ __attribute__((no_sanitize("undefined")))
|
|||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
|
||||
{
|
||||
struct mgcp_rtp_state *state = &conn->state;
|
||||
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
|
||||
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
||||
|
||||
*expected = state->stats.cycles + state->stats.max_seq;
|
||||
*expected = *expected - state->stats.base_seq + 1;
|
||||
|
@ -80,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
|
|||
int ploss;
|
||||
int nchars;
|
||||
|
||||
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
|
||||
struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
|
||||
struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
|
||||
struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
|
||||
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
||||
struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
|
||||
struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
|
||||
struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
|
||||
|
||||
calc_loss(conn, &expected, &ploss);
|
||||
jitter = calc_jitter(&conn->state);
|
||||
|
@ -99,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
|
|||
str += nchars;
|
||||
str_len -= nchars;
|
||||
|
||||
if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
|
||||
if (conn->conn->endp->trunk->cfg->osmux.usage != OSMUX_USAGE_OFF) {
|
||||
/* Error Counter */
|
||||
nchars = snprintf(str, str_len,
|
||||
"\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
|
||||
|
@ -112,9 +112,12 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
|
|||
str_len -= nchars;
|
||||
|
||||
if (conn->osmux.state == OSMUX_STATE_ENABLED) {
|
||||
struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
|
||||
osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
|
||||
osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
|
||||
snprintf(str, str_len,
|
||||
"\r\nX-Osmux-ST: CR=%u, BR=%u",
|
||||
conn->osmux.stats.chunks, conn->osmux.stats.octets);
|
||||
"\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
|
||||
osmux_chunks_rx->current, osmux_octets_rx->current);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,17 +111,12 @@ static int config_write_mgcp(struct vty *vty)
|
|||
VTY_NEWLINE);
|
||||
} else
|
||||
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
|
||||
if (trunk->audio_fmtp_extra)
|
||||
vty_out(vty, " sdp audio fmtp-extra %s%s",
|
||||
trunk->audio_fmtp_extra, VTY_NEWLINE);
|
||||
vty_out(vty, " %ssdp audio-payload send-ptime%s",
|
||||
trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
|
||||
vty_out(vty, " %ssdp audio-payload send-name%s",
|
||||
trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
|
||||
vty_out(vty, " number endpoints %u%s",
|
||||
trunk->v.vty_number_endpoints, VTY_NEWLINE);
|
||||
vty_out(vty, " %sallow-transcoding%s",
|
||||
trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
|
||||
if (strlen(g_cfg->call_agent_addr))
|
||||
vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
|
||||
VTY_NEWLINE);
|
||||
|
@ -129,7 +124,7 @@ static int config_write_mgcp(struct vty *vty)
|
|||
vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
|
||||
VTY_NEWLINE);
|
||||
|
||||
switch (g_cfg->osmux) {
|
||||
switch (g_cfg->osmux.usage) {
|
||||
case OSMUX_USAGE_ON:
|
||||
vty_out(vty, " osmux on%s", VTY_NEWLINE);
|
||||
break;
|
||||
|
@ -141,17 +136,23 @@ static int config_write_mgcp(struct vty *vty)
|
|||
vty_out(vty, " osmux off%s", VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
if (g_cfg->osmux) {
|
||||
vty_out(vty, " osmux bind-ip %s%s",
|
||||
g_cfg->osmux_addr, VTY_NEWLINE);
|
||||
if (g_cfg->osmux.usage != OSMUX_USAGE_OFF) {
|
||||
if (g_cfg->osmux.local_addr_v4)
|
||||
vty_out(vty, " osmux bind-ip %s%s",
|
||||
g_cfg->osmux.local_addr_v4, VTY_NEWLINE);
|
||||
if (g_cfg->osmux.local_addr_v6)
|
||||
vty_out(vty, " osmux bind-ip-v6 %s%s",
|
||||
g_cfg->osmux.local_addr_v6, VTY_NEWLINE);
|
||||
vty_out(vty, " osmux batch-factor %d%s",
|
||||
g_cfg->osmux_batch, VTY_NEWLINE);
|
||||
g_cfg->osmux.batch_factor, VTY_NEWLINE);
|
||||
vty_out(vty, " osmux batch-size %u%s",
|
||||
g_cfg->osmux_batch_size, VTY_NEWLINE);
|
||||
g_cfg->osmux.batch_size, VTY_NEWLINE);
|
||||
vty_out(vty, " osmux port %u%s",
|
||||
g_cfg->osmux_port, VTY_NEWLINE);
|
||||
g_cfg->osmux.local_port, VTY_NEWLINE);
|
||||
vty_out(vty, " osmux dummy %s%s",
|
||||
g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
|
||||
g_cfg->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
|
||||
vty_out(vty, " osmux peer-behind-nat %s%s",
|
||||
g_cfg->osmux.peer_behind_nat ? "on" : "off", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_cfg->conn_timeout)
|
||||
|
@ -169,11 +170,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
|
|||
struct rate_ctr *rx_packets, *rx_bytes;
|
||||
struct rate_ctr *dropped_packets;
|
||||
|
||||
tx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
|
||||
tx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
|
||||
rx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
|
||||
rx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
|
||||
dropped_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_DROPPED_PACKETS_CTR);
|
||||
tx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
|
||||
tx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
|
||||
rx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
||||
rx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
|
||||
dropped_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_DROPPED_PACKETS_CTR);
|
||||
|
||||
vty_out(vty,
|
||||
" Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
|
||||
|
@ -183,20 +184,44 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
|
|||
" Payload Type: %d Rate: %u Channels: %d %s"
|
||||
" Frame Duration: %u Frame Denominator: %u%s"
|
||||
" FPP: %d Packet Duration: %u%s"
|
||||
" FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
|
||||
" Audio-Name: %s Sub-Type: %s%s"
|
||||
" Output-Enabled: %d Force-PTIME: %d%s",
|
||||
tx_packets->current, tx_bytes->current, VTY_NEWLINE,
|
||||
rx_packets->current, rx_bytes->current, VTY_NEWLINE,
|
||||
state->in_stream.err_ts_ctr->current,
|
||||
state->out_stream.err_ts_ctr->current,
|
||||
VTY_NEWLINE,
|
||||
VTY_NEWLINE,
|
||||
dropped_packets->current, VTY_NEWLINE,
|
||||
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
|
||||
codec->frame_duration_num, codec->frame_duration_den,
|
||||
VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
|
||||
VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
|
||||
VTY_NEWLINE, codec->audio_name,
|
||||
codec->subtype_name, VTY_NEWLINE, end->output_enabled,
|
||||
end->force_output_ptime, VTY_NEWLINE);
|
||||
if (mgcp_conn_rtp_is_osmux(conn)) {
|
||||
struct rate_ctr *rx_chunks, *rx_octets, *rtp_tx, *rtp_tx_dropped, *octets_tx;
|
||||
rx_chunks = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_CHUNKS_RX_CTR);
|
||||
rx_octets = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_OCTETS_RX_CTR);
|
||||
rtp_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_CTR);
|
||||
rtp_tx_dropped = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
|
||||
octets_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_AMR_OCTETS_TX_CTR);
|
||||
vty_out(vty,
|
||||
" Osmux:%s"
|
||||
" State: %s%s"
|
||||
" Local CID: %d%s"
|
||||
" Remote CID: %d%s"
|
||||
" Chunks received: %" PRIu64 " (%" PRIu64 " bytes total)%s"
|
||||
" RTP Packets encoded (Tx): %" PRIu64 " (%" PRIu64 " AMR octets total)%s"
|
||||
" AMR payloads Dropped (Tx): %" PRIu64 "%s",
|
||||
VTY_NEWLINE, osmux_state_str(conn->osmux.state), VTY_NEWLINE,
|
||||
conn->osmux.local_cid_allocated ? conn->osmux.local_cid : -1, VTY_NEWLINE,
|
||||
conn->osmux.remote_cid_present ? conn->osmux.remote_cid : -1, VTY_NEWLINE,
|
||||
rx_chunks->current, rx_octets->current, VTY_NEWLINE,
|
||||
rtp_tx->current, octets_tx->current, VTY_NEWLINE,
|
||||
rtp_tx_dropped->current, VTY_NEWLINE
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
|
||||
|
@ -289,6 +314,14 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
|
|||
" %25n: %10c (%S/s %M/m %H/h %D/d) %d",
|
||||
ratectr->all_rtp_conn_stats);
|
||||
}
|
||||
if (ratectr->all_osmux_conn_stats) {
|
||||
vty_out(vty, " %s:%s",
|
||||
ratectr->all_osmux_conn_stats->desc->group_description,
|
||||
VTY_NEWLINE);
|
||||
vty_out_rate_ctr_group_fmt(vty,
|
||||
" %25n: %10c (%S/s %M/m %H/h %D/d) %d",
|
||||
ratectr->all_osmux_conn_stats);
|
||||
}
|
||||
|
||||
if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
|
||||
vty_out(vty, " %s:%s",
|
||||
|
@ -342,7 +375,7 @@ static int mgcp_show(struct vty *vty, int argc, const char **argv,
|
|||
llist_for_each_entry(trunk, &g_cfg->trunks, entry)
|
||||
dump_trunk(vty, trunk, show_stats, active_only);
|
||||
|
||||
if (g_cfg->osmux)
|
||||
if (g_cfg->osmux.usage != OSMUX_USAGE_OFF)
|
||||
vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
|
||||
VTY_NEWLINE);
|
||||
|
||||
|
@ -475,6 +508,7 @@ DEFUN_DEPRECATED(cfg_mgcp_bind_early,
|
|||
BIND_STR
|
||||
"Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'bind early (0|1)' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -644,53 +678,40 @@ DEFUN_USRATTR(cfg_mgcp_no_rtp_force_ptime,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
|
||||
cfg_mgcp_sdp_fmtp_extra_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"sdp audio fmtp-extra .NAME",
|
||||
"Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
|
||||
"Extra Information\n")
|
||||
{
|
||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
OSMO_ASSERT(trunk);
|
||||
char *txt = argv_concat(argv, argc, 0);
|
||||
if (!txt)
|
||||
return CMD_WARNING;
|
||||
|
||||
osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
|
||||
talloc_free(txt);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_mgcp_allow_transcoding,
|
||||
cfg_mgcp_allow_transcoding_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"allow-transcoding", "Allow transcoding\n")
|
||||
{
|
||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
OSMO_ASSERT(trunk);
|
||||
trunk->no_audio_transcoding = 0;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_mgcp_no_allow_transcoding,
|
||||
cfg_mgcp_no_allow_transcoding_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"no allow-transcoding", NO_STR "Allow transcoding\n")
|
||||
{
|
||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
OSMO_ASSERT(trunk);
|
||||
trunk->no_audio_transcoding = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define SDP_STR "SDP File related options\n"
|
||||
#define AUDIO_STR "Audio payload options\n"
|
||||
|
||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_fmtp_extra,
|
||||
cfg_mgcp_sdp_fmtp_extra_cmd,
|
||||
"sdp audio fmtp-extra .NAME",
|
||||
SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
|
||||
{
|
||||
vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_DEPRECATED(cfg_mgcp_allow_transcoding,
|
||||
cfg_mgcp_allow_transcoding_cmd,
|
||||
"allow-transcoding", "Allow transcoding\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
|
||||
cfg_mgcp_no_allow_transcoding_cmd,
|
||||
"no allow-transcoding", NO_STR "Allow transcoding\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
|
||||
cfg_mgcp_sdp_payload_number_cmd,
|
||||
"sdp audio-payload number <0-255>",
|
||||
SDP_STR AUDIO_STR "Number\n" "Payload number\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -704,6 +725,7 @@ DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_name,
|
|||
"sdp audio-payload name NAME",
|
||||
SDP_STR AUDIO_STR "Name\n" "Payload name\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -764,6 +786,7 @@ DEFUN_DEPRECATED(cfg_mgcp_loop,
|
|||
"loop (0|1)",
|
||||
"Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1028,30 +1051,17 @@ static int config_write_trunk(struct vty *vty)
|
|||
VTY_NEWLINE);
|
||||
} else
|
||||
vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
|
||||
if (trunk->audio_fmtp_extra)
|
||||
vty_out(vty, " sdp audio fmtp-extra %s%s",
|
||||
trunk->audio_fmtp_extra, VTY_NEWLINE);
|
||||
vty_out(vty, " %sallow-transcoding%s",
|
||||
trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_trunk_sdp_fmtp_extra,
|
||||
DEFUN_DEPRECATED(cfg_trunk_sdp_fmtp_extra,
|
||||
cfg_trunk_sdp_fmtp_extra_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"sdp audio fmtp-extra .NAME",
|
||||
"Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
|
||||
"Extra Information\n")
|
||||
SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
|
||||
{
|
||||
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);
|
||||
vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1060,6 +1070,7 @@ DEFUN_DEPRECATED(cfg_trunk_payload_number,
|
|||
"sdp audio-payload number <0-255>",
|
||||
SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1072,6 +1083,7 @@ DEFUN_DEPRECATED(cfg_trunk_payload_name,
|
|||
"sdp audio-payload name NAME",
|
||||
SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1084,6 +1096,7 @@ DEFUN_DEPRECATED(cfg_trunk_loop,
|
|||
"loop (0|1)",
|
||||
"Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
|
||||
{
|
||||
vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1281,23 +1294,19 @@ DEFUN_ATTR(cfg_trunk_no_rtp_keepalive,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_trunk_allow_transcoding,
|
||||
cfg_trunk_allow_transcoding_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"allow-transcoding", "Allow transcoding\n")
|
||||
DEFUN_DEPRECATED(cfg_trunk_allow_transcoding,
|
||||
cfg_trunk_allow_transcoding_cmd,
|
||||
"allow-transcoding", "Allow transcoding\n")
|
||||
{
|
||||
struct mgcp_trunk *trunk = vty->index;
|
||||
trunk->no_audio_transcoding = 0;
|
||||
vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_USRATTR(cfg_trunk_no_allow_transcoding,
|
||||
cfg_trunk_no_allow_transcoding_cmd,
|
||||
X(MGW_CMD_ATTR_NEWCONN),
|
||||
"no allow-transcoding", NO_STR "Allow transcoding\n")
|
||||
DEFUN_DEPRECATED(cfg_trunk_no_allow_transcoding,
|
||||
cfg_trunk_no_allow_transcoding_cmd,
|
||||
"no allow-transcoding", NO_STR "Allow transcoding\n")
|
||||
{
|
||||
struct mgcp_trunk *trunk = vty->index;
|
||||
trunk->no_audio_transcoding = 1;
|
||||
vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1539,12 +1548,12 @@ DEFUN(cfg_mgcp_osmux,
|
|||
OSMO_ASSERT(trunk);
|
||||
|
||||
if (strcmp(argv[0], "off") == 0) {
|
||||
g_cfg->osmux = OSMUX_USAGE_OFF;
|
||||
g_cfg->osmux.usage = OSMUX_USAGE_OFF;
|
||||
return CMD_SUCCESS;
|
||||
} else if (strcmp(argv[0], "on") == 0)
|
||||
g_cfg->osmux = OSMUX_USAGE_ON;
|
||||
g_cfg->osmux.usage = OSMUX_USAGE_ON;
|
||||
else if (strcmp(argv[0], "only") == 0)
|
||||
g_cfg->osmux = OSMUX_USAGE_ONLY;
|
||||
g_cfg->osmux.usage = OSMUX_USAGE_ONLY;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
||||
|
@ -1552,12 +1561,29 @@ DEFUN(cfg_mgcp_osmux,
|
|||
|
||||
DEFUN(cfg_mgcp_osmux_ip,
|
||||
cfg_mgcp_osmux_ip_cmd,
|
||||
"osmux bind-ip " VTY_IPV46_CMD,
|
||||
"osmux bind-ip " VTY_IPV4_CMD,
|
||||
OSMUX_STR IP_STR
|
||||
"IPv4 Address to bind to\n")
|
||||
{
|
||||
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v4, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_osmux_ip_v6,
|
||||
cfg_mgcp_osmux_ip_v6_cmd,
|
||||
"osmux bind-ip-v6 " VTY_IPV6_CMD,
|
||||
OSMUX_STR IP_STR
|
||||
"IPv4 Address to bind to\n"
|
||||
"IPv6 Address to bind to\n")
|
||||
{
|
||||
osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
|
||||
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v6, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_osmux_port,
|
||||
cfg_mgcp_osmux_port_cmd,
|
||||
"osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
|
||||
{
|
||||
g_cfg->osmux.local_port = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1566,7 +1592,7 @@ DEFUN(cfg_mgcp_osmux_batch_factor,
|
|||
"osmux batch-factor <1-8>",
|
||||
OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
|
||||
{
|
||||
g_cfg->osmux_batch = atoi(argv[0]);
|
||||
g_cfg->osmux.batch_factor = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1575,15 +1601,7 @@ DEFUN(cfg_mgcp_osmux_batch_size,
|
|||
"osmux batch-size <1-65535>",
|
||||
OSMUX_STR "batch size\n" "Batch size in bytes\n")
|
||||
{
|
||||
g_cfg->osmux_batch_size = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_osmux_port,
|
||||
cfg_mgcp_osmux_port_cmd,
|
||||
"osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
|
||||
{
|
||||
g_cfg->osmux_port = atoi(argv[0]);
|
||||
g_cfg->osmux.batch_size = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1594,9 +1612,24 @@ DEFUN(cfg_mgcp_osmux_dummy,
|
|||
"Disable dummy padding\n")
|
||||
{
|
||||
if (strcmp(argv[0], "on") == 0)
|
||||
g_cfg->osmux_dummy = 1;
|
||||
g_cfg->osmux.dummy_padding = true;
|
||||
else if (strcmp(argv[0], "off") == 0)
|
||||
g_cfg->osmux_dummy = 0;
|
||||
g_cfg->osmux.dummy_padding = false;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_osmux_peer_behind_nat,
|
||||
cfg_mgcp_osmux_peer_behind_nat_cmd,
|
||||
"osmux peer-behind-nat (on|off)",
|
||||
OSMUX_STR "Define whether peer is behind NAT\n"
|
||||
"Peer is behind NAT\n"
|
||||
"Peer is NOT behind NAT\n")
|
||||
{
|
||||
if (strcmp(argv[0], "on") == 0)
|
||||
g_cfg->osmux.peer_behind_nat = true;
|
||||
else if (strcmp(argv[0], "off") == 0)
|
||||
g_cfg->osmux.peer_behind_nat = false;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -1686,10 +1719,12 @@ int mgcp_vty_init(void)
|
|||
install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_osmux_peer_behind_nat_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
|
||||
|
@ -1734,9 +1769,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
|
|||
int rc;
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
cfg->osmux_port = OSMUX_PORT;
|
||||
cfg->osmux_batch = 4;
|
||||
cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
|
||||
cfg->osmux.local_port = OSMUX_DEFAULT_PORT;
|
||||
cfg->osmux.batch_factor = 4;
|
||||
cfg->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
|
||||
|
||||
g_cfg = cfg;
|
||||
rc = vty_read_config_file(config_file, NULL);
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include <osmocom/mgcp/debug.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_ctrl.h>
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
@ -51,7 +50,7 @@
|
|||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
|
@ -83,7 +82,7 @@ static int daemonize = 0;
|
|||
|
||||
const char *osmomgw_copyright =
|
||||
"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
|
||||
"Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
|
||||
"Copyright (C) 2017-2022 by sysmocom s.f.m.c. GmbH\r\n"
|
||||
"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
|
||||
"Philipp Maier\r\n\r\n"
|
||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||
|
@ -95,7 +94,7 @@ static char *config_file = "osmo-mgw.cfg";
|
|||
/* used by msgb and mgcp */
|
||||
void *tall_mgw_ctx = NULL;
|
||||
|
||||
static void print_help()
|
||||
static void print_help(void)
|
||||
{
|
||||
printf("Some useful options:\n");
|
||||
printf(" -h --help is printing this text.\n");
|
||||
|
@ -281,6 +280,31 @@ int mgcp_vty_go_parent(struct vty *vty)
|
|||
return vty->node;
|
||||
}
|
||||
|
||||
static void signal_handler(int signum)
|
||||
{
|
||||
fprintf(stdout, "signal %u received\n", signum);
|
||||
|
||||
switch (signum) {
|
||||
case SIGABRT:
|
||||
/* in case of abort, we want to obtain a talloc report and
|
||||
* then run default SIGABRT handler, who will generate coredump
|
||||
* and abort the process. abort() should do this for us after we
|
||||
* return, but program wouldn't exit if an external SIGABRT is
|
||||
* received.
|
||||
*/
|
||||
talloc_report(tall_vty_ctx, stderr);
|
||||
talloc_report_full(tall_mgw_ctx, stderr);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
raise(SIGABRT);
|
||||
break;
|
||||
case SIGUSR1:
|
||||
talloc_report(tall_vty_ctx, stderr);
|
||||
talloc_report_full(tall_mgw_ctx, stderr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct vty_app_info vty_info = {
|
||||
.name = "OsmoMGW",
|
||||
|
@ -295,13 +319,22 @@ static const struct log_info_cat log_categories[] = {
|
|||
.name = "DRTP",
|
||||
.description = "RTP stream handling",
|
||||
.color = "\033[1;30m",
|
||||
.enabled = 1,.loglevel = LOGL_NOTICE,
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DE1] = {
|
||||
.name = "DE1",
|
||||
.description = "E1 line handling",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,.loglevel = LOGL_NOTICE,
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DOSMUX] = {
|
||||
.name = "DOSMUX",
|
||||
.description = "Osmux (Osmocom RTP multiplexing)",
|
||||
.color = "\033[1;32m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -320,6 +353,8 @@ int main(int argc, char **argv)
|
|||
|
||||
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
|
||||
|
||||
signal(SIGABRT, &signal_handler);
|
||||
signal(SIGUSR1, &signal_handler);
|
||||
osmo_init_ignore_signals();
|
||||
osmo_init_logging2(tall_mgw_ctx, &log_info);
|
||||
libosmo_abis_init(tall_mgw_ctx);
|
||||
|
@ -352,12 +387,11 @@ int main(int argc, char **argv)
|
|||
return rc;
|
||||
|
||||
/* start telnet after reading config for vty_get_bind_addr() */
|
||||
rc = telnet_init_dynif(tall_mgw_ctx, NULL,
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
|
||||
rc = telnet_init_default(tall_mgw_ctx, NULL, OSMO_VTY_PORT_MGW);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
|
||||
cfg->ctrl = ctrl_interface_setup(cfg, OSMO_CTRL_PORT_MGW, NULL);
|
||||
if (!cfg->ctrl) {
|
||||
fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
|
||||
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
|
||||
|
|
|
@ -34,11 +34,11 @@ DISTCLEANFILES = \
|
|||
$(NULL)
|
||||
|
||||
if ENABLE_EXT_TESTS
|
||||
python-tests: $(BUILT_SOURCES)
|
||||
python-tests: $(top_builddir)/src/osmo-mgw/osmo-mgw
|
||||
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
|
||||
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
|
||||
else
|
||||
python-tests: $(BUILT_SOURCES)
|
||||
python-tests:
|
||||
echo "Not running python-based tests (determined at configure-time)"
|
||||
endif
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ AM_CFLAGS = \
|
|||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@ -44,3 +45,6 @@ mgcp_test_LDADD = \
|
|||
$(LIBOSMONETIF_LIBS) \
|
||||
-lm \
|
||||
$(NULL)
|
||||
|
||||
update_exp:
|
||||
$(builddir)/mgcp_test >$(srcdir)/mgcp_test.ok
|
||||
|
|
|
@ -77,6 +77,8 @@ static void test_strline(void)
|
|||
#define AUEP1_RET "500 158663169 FAIL\r\n"
|
||||
#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
|
||||
#define AUEP2_RET "500 18983213 FAIL\r\n"
|
||||
#define AUEP_NULL "AUEP 18983215 null@mgw MGCP 1.0\r\n"
|
||||
#define AUEP_NULL_RET "200 18983215 OK\r\n"
|
||||
#define EMPTY "\r\n"
|
||||
#define EMPTY_RET NULL
|
||||
#define SHORT "CRCX \r\n"
|
||||
|
@ -125,7 +127,6 @@ static void test_strline(void)
|
|||
"t=0 0\r\n" \
|
||||
"m=audio 16006 RTP/AVP 97\r\n" \
|
||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||
"a=fmtp:126 0/1/2\r\n" \
|
||||
"a=ptime:40\r\n"
|
||||
|
||||
#define MDCX4_ADDR0000 \
|
||||
|
@ -274,6 +275,12 @@ static void test_strline(void)
|
|||
|
||||
#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
|
||||
|
||||
#define MDCX_NULL \
|
||||
"MDCX 9 null@mgw MGCP 1.0\r\n" \
|
||||
"I: %s\n"
|
||||
|
||||
#define MDCX_NULL_RET "502 9 FAIL\r\n"
|
||||
|
||||
#define SHORT2 "CRCX 1"
|
||||
#define SHORT2_RET "510 000000 FAIL\r\n"
|
||||
#define SHORT3 "CRCX 1 1@mgw"
|
||||
|
@ -328,7 +335,6 @@ static void test_strline(void)
|
|||
"t=0 0\r\n" \
|
||||
"m=audio 16006 RTP/AVP 97\r\n" \
|
||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||
"a=fmtp:126 0/1/2\r\n" \
|
||||
"a=ptime:40\r\n"
|
||||
|
||||
#define CRCX_ZYN \
|
||||
|
@ -392,6 +398,13 @@ static void test_strline(void)
|
|||
#define DLCX_RET_OSMUX DLCX_RET \
|
||||
"X-Osmo-CP: EC TI=0, TO=0\r\n"
|
||||
|
||||
#define DLCX_NULL \
|
||||
"DLCX 8 null@mgw MGCP 1.0\r\n" \
|
||||
"I: %s\r\n" \
|
||||
"C: 2\r\n"
|
||||
|
||||
#define DLCX_NULL_RET "502 8 FAIL\r\n"
|
||||
|
||||
#define RQNT \
|
||||
"RQNT 186908780 1@mgw MGCP 1.0\r\n" \
|
||||
"X: B244F267488\r\n" \
|
||||
|
@ -405,6 +418,13 @@ static void test_strline(void)
|
|||
#define RQNT1_RET "200 186908780 OK\r\n"
|
||||
#define RQNT2_RET "200 186908781 OK\r\n"
|
||||
|
||||
#define RQNT_NULL \
|
||||
"RQNT 186908782 null@mgw MGCP 1.0\r\n" \
|
||||
"X: B244F267488\r\n" \
|
||||
"S: D/9\r\n"
|
||||
|
||||
#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
|
||||
|
||||
#define PTYPE_IGNORE 0 /* == default initializer */
|
||||
#define PTYPE_NONE 128
|
||||
#define PTYPE_NYI PTYPE_NONE
|
||||
|
@ -545,12 +565,25 @@ static void test_strline(void)
|
|||
"m=audio 16008 RTP/AVP 0\r\n" \
|
||||
"a=ptime:20\r\n"
|
||||
|
||||
#define CRCX_NULL \
|
||||
"CRCX 2 null@mgw MGCP 1.0\r\n" \
|
||||
"m: recvonly\r\n" \
|
||||
"C: 2\r\n" \
|
||||
"L: p:20\r\n" \
|
||||
"\r\n" \
|
||||
"v=0\r\n" \
|
||||
"c=IN IP4 123.12.12.123\r\n" \
|
||||
"m=audio 5904 RTP/AVP 97\r\n" \
|
||||
"a=rtpmap:97 GSM-EFR/8000\r\n" \
|
||||
"a=ptime:40\r\n"
|
||||
|
||||
#define CRCX_NULL_RET "502 2 FAIL\r\n"
|
||||
|
||||
struct mgcp_test {
|
||||
const char *name;
|
||||
const char *req;
|
||||
const char *exp_resp;
|
||||
int ptype;
|
||||
const char *extra_fmtp;
|
||||
};
|
||||
|
||||
static const struct mgcp_test tests[] = {
|
||||
|
@ -578,14 +611,18 @@ static const struct mgcp_test tests[] = {
|
|||
{"RQNT1", RQNT, RQNT1_RET},
|
||||
{"RQNT2", RQNT2, RQNT2_RET},
|
||||
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
|
||||
{"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
|
||||
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
|
||||
"a=fmtp:126 0/1/2"},
|
||||
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
|
||||
{"CRCX", CRCX, CRCX_FMTP_RET, 97},
|
||||
{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
|
||||
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
|
||||
{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
|
||||
{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
|
||||
{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
|
||||
{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
|
||||
{"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
|
||||
{"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
|
||||
{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
|
||||
{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
|
||||
{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
|
||||
};
|
||||
|
||||
static const struct mgcp_test retransmit[] = {
|
||||
|
@ -616,12 +653,13 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
|
|||
|
||||
static int dummy_packets = 0;
|
||||
/* override and forward */
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
|
||||
{
|
||||
uint32_t dest_host =
|
||||
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
|
||||
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
|
||||
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
|
||||
const uint8_t *buf = msgb_data(msg);
|
||||
size_t len = msgb_length(msg);
|
||||
|
||||
if (len == sizeof(rtp_dummy_payload)
|
||||
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
|
||||
|
@ -635,6 +673,8 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
|||
OSMO_ASSERT(dest_host);
|
||||
OSMO_ASSERT(dest_port);
|
||||
|
||||
msgb_free(msg);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -790,9 +830,6 @@ static void test_messages(void)
|
|||
|
||||
dummy_packets = 0;
|
||||
|
||||
osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
|
||||
t->extra_fmtp);
|
||||
|
||||
inp = create_msg(t->req, last_conn_id);
|
||||
msg = mgcp_handle_message(cfg, inp);
|
||||
msgb_free(inp);
|
||||
|
@ -838,7 +875,7 @@ static void test_messages(void)
|
|||
if (endp->local_options.pkt_period_min ||
|
||||
endp->local_options.pkt_period_max)
|
||||
printf
|
||||
("Requested packetetization period: "
|
||||
("Requested packetization period: "
|
||||
"%d-%d\n",
|
||||
endp->local_options.pkt_period_min,
|
||||
endp->
|
||||
|
@ -1071,7 +1108,7 @@ static void test_packet_loss_calc(void)
|
|||
"test-connection");
|
||||
conn = mgcp_conn_get_rtp(&endp, _conn->id);
|
||||
state = &conn->state;
|
||||
packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
|
||||
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
|
||||
|
||||
state->stats.initialized = 1;
|
||||
state->stats.base_seq = pl_test_dat[i].base_seq;
|
||||
|
@ -1467,7 +1504,6 @@ static void test_multilple_codec(void)
|
|||
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
|
||||
last_endpoint[0] = '\0';
|
||||
inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
|
||||
trunk->no_audio_transcoding = 1;
|
||||
resp = mgcp_handle_message(cfg, inp);
|
||||
OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
|
||||
sizeof(conn_id)) == 0);
|
||||
|
@ -1492,7 +1528,7 @@ static void test_multilple_codec(void)
|
|||
conn = mgcp_conn_get_rtp(endp, conn_id);
|
||||
OSMO_ASSERT(conn);
|
||||
OSMO_ASSERT(conn->end.codec->payload_type == 3);
|
||||
OSMO_ASSERT(conn->end.rtp_port == htons(16434));
|
||||
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
inet_aton("8.8.8.8", &addr);
|
||||
OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
|
||||
|
@ -1511,7 +1547,6 @@ static void test_multilple_codec(void)
|
|||
|
||||
last_endpoint[0] = '\0';
|
||||
inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
|
||||
trunk->no_audio_transcoding = 0;
|
||||
resp = mgcp_handle_message(cfg, inp);
|
||||
OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
|
||||
sizeof(conn_id)) == 0);
|
||||
|
@ -1632,7 +1667,8 @@ static void test_osmux_cid(void)
|
|||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
id = osmux_cid_pool_get_next();
|
||||
OSMO_ASSERT(id == i);
|
||||
/* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
|
||||
OSMO_ASSERT(id == ((i + 1) & 0xff));
|
||||
OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
|
||||
}
|
||||
|
||||
|
@ -1768,26 +1804,25 @@ static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
|
|||
.amr_octet_aligned_present = false,
|
||||
};
|
||||
|
||||
struct testcase_mgcp_codec_pt_translate_codec {
|
||||
struct testcase_mgcp_codec_decide_codec {
|
||||
int payload_type;
|
||||
const char *audio_name;
|
||||
const struct mgcp_codec_param *param;
|
||||
int expect_rc;
|
||||
};
|
||||
|
||||
struct testcase_mgcp_codec_pt_translate_expect {
|
||||
bool end;
|
||||
struct testcase_mgcp_codec_decide_expect {
|
||||
int payload_type_map[2];
|
||||
};
|
||||
|
||||
struct testcase_mgcp_codec_pt_translate {
|
||||
struct testcase_mgcp_codec_decide {
|
||||
const char *descr;
|
||||
/* two conns on an endpoint, each with N configured codecs */
|
||||
struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
|
||||
struct testcase_mgcp_codec_pt_translate_expect expect[32];
|
||||
struct testcase_mgcp_codec_decide_codec codecs[2][10];
|
||||
struct testcase_mgcp_codec_decide_expect expect[2];
|
||||
};
|
||||
|
||||
static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
|
||||
static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
|
||||
{
|
||||
.descr = "same order, but differing payload type numbers",
|
||||
.codecs = {
|
||||
|
@ -1804,10 +1839,7 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, 96}, },
|
||||
{ .payload_type_map = {0, 0}, },
|
||||
{ .payload_type_map = {111, 97} },
|
||||
{ .payload_type_map = {123, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {112, 96}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1825,11 +1857,8 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, 96}, },
|
||||
{ .payload_type_map = {0, 0}, },
|
||||
{ .payload_type_map = {111, 97} },
|
||||
{ .payload_type_map = {123, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 97}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1847,10 +1876,8 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {96, 97}, },
|
||||
{ .payload_type_map = {97, 96}, },
|
||||
{ .payload_type_map = {0, 0}, },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {96, 97}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1866,10 +1893,8 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, -EINVAL}, },
|
||||
{ .payload_type_map = {0, -EINVAL}, },
|
||||
{ .payload_type_map = {111, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {-EINVAL, -EINVAL}, },
|
||||
{ .payload_type_map = {-EINVAL, 96}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1886,28 +1911,60 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, -EINVAL}, },
|
||||
{ .payload_type_map = {0, -EINVAL}, },
|
||||
{ .payload_type_map = {111, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {-EINVAL, -EINVAL}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with differing octet-aligned settings",
|
||||
.descr = "test AMR with differing octet-aligned settings (both <-> both)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 121}, },
|
||||
{ .payload_type_map = {112, 122} },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with differing octet-aligned settings (oa <-> both)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 121}, },
|
||||
{ .payload_type_map = {111, 121}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with missing octet-aligned settings (defaults to 0)",
|
||||
.descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, 122}, },
|
||||
{ .payload_type_map = {112, 122}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
|
@ -1918,22 +1975,54 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with NULL param (defaults to 0)",
|
||||
.descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
{ 111, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with NULL param (oa <-> null)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 112, "AMR/8000", &amr_param_octet_aligned_true, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", NULL, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 122}, },
|
||||
{ .end = true },
|
||||
/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
|
||||
{ .payload_type_map = {112, 122} },
|
||||
{ .payload_type_map = {112, 122}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
.descr = "test AMR with NULL param (bwe <-> null)",
|
||||
.codecs = {
|
||||
{
|
||||
{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
|
||||
},
|
||||
{
|
||||
{ 122, "AMR/8000", NULL, },
|
||||
},
|
||||
},
|
||||
.expect = {
|
||||
/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
|
||||
{ .payload_type_map = {112, 122} },
|
||||
{ .payload_type_map = {112, 122}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1951,11 +2040,8 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, 96}, },
|
||||
{ .payload_type_map = {0, 0}, },
|
||||
{ .payload_type_map = {111, 97} },
|
||||
{ .payload_type_map = {123, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 97}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1973,11 +2059,8 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {112, 96}, },
|
||||
{ .payload_type_map = {0, 0}, },
|
||||
{ .payload_type_map = {111, 97} },
|
||||
{ .payload_type_map = {123, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 97}, },
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1995,45 +2078,98 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
|
|||
},
|
||||
.expect = {
|
||||
{ .payload_type_map = {111, 121}, },
|
||||
{ .payload_type_map = {112, -EINVAL} },
|
||||
{ .payload_type_map = {113, -EINVAL} },
|
||||
{ .end = true },
|
||||
{ .payload_type_map = {111, 121} },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static void test_mgcp_codec_pt_translate(void)
|
||||
static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
|
||||
const struct testcase_mgcp_codec_decide_expect *expect)
|
||||
{
|
||||
bool ok = true;
|
||||
int payload_type_conn_src;
|
||||
int payload_type_conn_dst;
|
||||
|
||||
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
|
||||
if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
|
||||
if (expect->payload_type_map[index_conn_src] == -EINVAL
|
||||
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
|
||||
printf(" codec decision failed (expected)!\n");
|
||||
else {
|
||||
printf(" ERROR: codec decision failed!\n");
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
printf(" Codec decision result:\n");
|
||||
if (conn[index_conn_src].end.codec) {
|
||||
payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
|
||||
printf(" conn[%u]: codec:%s, pt:%d\n",
|
||||
index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
|
||||
} else {
|
||||
payload_type_conn_src = -EINVAL;
|
||||
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
|
||||
}
|
||||
|
||||
if (conn[index_conn_dst].end.codec) {
|
||||
payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
|
||||
printf(" conn[%u]: codec:%s, pt:%d\n",
|
||||
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
|
||||
payload_type_conn_dst);
|
||||
} else {
|
||||
payload_type_conn_dst = -EINVAL;
|
||||
printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
|
||||
}
|
||||
|
||||
if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
|
||||
printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
|
||||
index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
|
||||
printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
|
||||
index_conn_dst, expect->payload_type_map[index_conn_dst],
|
||||
payload_type_conn_dst);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void test_mgcp_codec_decide(void)
|
||||
{
|
||||
int i;
|
||||
bool ok = true;
|
||||
printf("\nTesting mgcp_codec_pt_translate()\n");
|
||||
bool ok_all = true;
|
||||
printf("\nTesting mgcp_codec_find_convertible()\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
|
||||
const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
|
||||
struct mgcp_conn_rtp conn[2] = {};
|
||||
for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
|
||||
const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
|
||||
struct mgcp_conn_rtp conn[2] = { };
|
||||
int rc;
|
||||
int conn_i;
|
||||
int c;
|
||||
bool ok = true;
|
||||
|
||||
printf("#%d: %s\n", i, t->descr);
|
||||
|
||||
/* Build testvector (add codecs to conn, set properties etc... */
|
||||
for (conn_i = 0; conn_i < 2; conn_i++) {
|
||||
printf(" - add codecs on conn%d:\n", conn_i);
|
||||
for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
|
||||
const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
|
||||
const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
|
||||
if (!codec->audio_name)
|
||||
break;
|
||||
|
||||
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
|
||||
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
|
||||
codec->param);
|
||||
|
||||
printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
|
||||
codec->param ?
|
||||
(codec->param->amr_octet_aligned_present?
|
||||
(codec->param->amr_octet_aligned ?
|
||||
" octet-aligned=1" : " octet-aligned=0")
|
||||
: " octet-aligned=unset")
|
||||
: "",
|
||||
rc);
|
||||
(codec->param->amr_octet_aligned_present ?
|
||||
(codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
|
||||
: " octet-aligned=unset")
|
||||
: "", rc);
|
||||
if (rc != codec->expect_rc) {
|
||||
printf(" ERROR: expected rc=%d\n", codec->expect_rc);
|
||||
ok = false;
|
||||
|
@ -2043,42 +2179,26 @@ static void test_mgcp_codec_pt_translate(void)
|
|||
printf(" (none)\n");
|
||||
}
|
||||
|
||||
for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
|
||||
const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
|
||||
int result;
|
||||
/* Run codec decision and check expectation */
|
||||
if (!codec_decision(conn, 0, 1, &t->expect[0]))
|
||||
ok = false;
|
||||
|
||||
if (expect->end)
|
||||
break;
|
||||
if (!codec_decision(conn, 1, 0, &t->expect[1]))
|
||||
ok = false;
|
||||
|
||||
result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
|
||||
printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
|
||||
expect->payload_type_map[0], result);
|
||||
if (result != expect->payload_type_map[1]) {
|
||||
printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
|
||||
ok = false;
|
||||
}
|
||||
if (ok)
|
||||
printf(" ===> SUCCESS: codec decision as expected!\n");
|
||||
else
|
||||
printf(" ===> FAIL: unexpected codec decision!\n");
|
||||
|
||||
/* If the expected result is an error, don't do reverse map test */
|
||||
if (expect->payload_type_map[1] < 0)
|
||||
continue;
|
||||
|
||||
result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
|
||||
printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
|
||||
expect->payload_type_map[1], result);
|
||||
if (result != expect->payload_type_map[0]) {
|
||||
printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (conn_i = 0; conn_i < 2; conn_i++)
|
||||
mgcp_codec_reset_all(&conn[conn_i]);
|
||||
if (!ok)
|
||||
ok_all = false;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(ok);
|
||||
OSMO_ASSERT(ok_all);
|
||||
}
|
||||
|
||||
void test_conn_id_matching()
|
||||
void test_conn_id_matching(void)
|
||||
{
|
||||
struct mgcp_endpoint endp = {};
|
||||
struct mgcp_conn *conn;
|
||||
|
@ -2118,7 +2238,7 @@ void test_conn_id_matching()
|
|||
talloc_free(conn);
|
||||
}
|
||||
|
||||
void test_e1_trunk_nr_from_epname()
|
||||
void test_e1_trunk_nr_from_epname(void)
|
||||
{
|
||||
unsigned int trunk_nr;
|
||||
int rc;
|
||||
|
@ -2168,7 +2288,7 @@ void test_e1_trunk_nr_from_epname()
|
|||
return;
|
||||
}
|
||||
|
||||
void test_mgcp_is_rtp_dummy_payload()
|
||||
void test_mgcp_is_rtp_dummy_payload(void)
|
||||
{
|
||||
/* realistic rtp packet */
|
||||
static const char rtp_payload[] =
|
||||
|
@ -2232,7 +2352,7 @@ int main(int argc, char **argv)
|
|||
test_osmux_cid();
|
||||
test_get_lco_identifier();
|
||||
test_check_local_cx_options(ctx);
|
||||
test_mgcp_codec_pt_translate();
|
||||
test_mgcp_codec_decide();
|
||||
test_conn_id_matching();
|
||||
test_e1_trunk_nr_from_epname();
|
||||
test_mgcp_is_rtp_dummy_payload();
|
||||
|
|
|
@ -525,6 +525,80 @@ Response matches our expectations.
|
|||
(response contains a connection id)
|
||||
Dummy packets: 2
|
||||
|
||||
================================================
|
||||
Testing AUEP_NULL
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
AUEP 18983215 null@mgw MGCP 1.0
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing CRCX_NULL
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
CRCX 2 null@mgw MGCP 1.0
|
||||
m: recvonly
|
||||
C: 2
|
||||
L: p:20
|
||||
|
||||
v=0
|
||||
c=IN IP4 123.12.12.123
|
||||
m=audio 5904 RTP/AVP 97
|
||||
a=rtpmap:97 GSM-EFR/8000
|
||||
a=ptime:40
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing MDCX_NULL
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 9 null@mgw MGCP 1.0
|
||||
I: %s
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing DLCX_NULL
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
DLCX 8 null@mgw MGCP 1.0
|
||||
I: %s
|
||||
C: 2
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing RQNT_NULL
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
RQNT 186908782 null@mgw MGCP 1.0
|
||||
X: B244F267488
|
||||
S: D/9
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing CRCX
|
||||
creating message from statically defined input:
|
||||
|
@ -1276,7 +1350,7 @@ p:10, a:PCMU -> p:10, a:PCMU
|
|||
p10, aPCMU -> (null)
|
||||
'10,a :PCMU' -> '(null)'
|
||||
|
||||
Testing mgcp_codec_pt_translate()
|
||||
Testing mgcp_codec_find_convertible()
|
||||
#0: same order, but differing payload type numbers
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
|
@ -1286,13 +1360,15 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:112
|
||||
conn[1]: codec:AMR, pt:96
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:96
|
||||
conn[0]: codec:AMR, pt:112
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#1: different order and different payload type numbers
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
|
@ -1302,13 +1378,15 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:PCMU, pt:0
|
||||
conn[1]: codec:PCMU, pt:0
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:GSM-HR-08, pt:97
|
||||
conn[0]: codec:GSM-HR-08, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#2: both sides have the same payload_type numbers assigned to differing codecs
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
|
@ -1318,12 +1396,15 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 96) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:PCMU, pt:0
|
||||
conn[1]: codec:PCMU, pt:0
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:GSM-HR-08, pt:97
|
||||
conn[0]: codec:GSM-HR-08, pt:96
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#3: conn0 has no codecs
|
||||
- add codecs on conn0:
|
||||
(none)
|
||||
|
@ -1331,9 +1412,13 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
codec decision failed (expected)!
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:96
|
||||
conn[0]: codec:none, pt:none
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#4: conn1 has no codecs
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
|
@ -1341,31 +1426,116 @@ Testing mgcp_codec_pt_translate()
|
|||
2: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
(none)
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
#5: test AMR with differing octet-aligned settings
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:112
|
||||
conn[1]: codec:none, pt:none
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
codec decision failed (expected)!
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#5: test AMR with differing octet-aligned settings (both <-> both)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
1: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=0 -> rc=0
|
||||
1: 121 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:111
|
||||
conn[1]: codec:AMR, pt:121
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:112
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#6: test AMR with differing octet-aligned settings (oa <-> both)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
|
||||
#6: test AMR with missing octet-aligned settings (defaults to 0)
|
||||
1: 121 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:111
|
||||
conn[1]: codec:AMR, pt:121
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:121
|
||||
conn[0]: codec:AMR, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#7: test AMR with differing octet-aligned settings (bwe <-> both)
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=0 -> rc=0
|
||||
1: 121 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:112
|
||||
conn[1]: codec:AMR, pt:122
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:112
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#8: test AMR with missing octet-aligned settings (oa <-> unset)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=unset -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
|
||||
#7: test AMR with NULL param (defaults to 0)
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:111
|
||||
conn[1]: codec:AMR, pt:122
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#9: test AMR with missing octet-aligned settings (bwe <-> unset)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
0: 111 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=unset -> rc=0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:111
|
||||
conn[1]: codec:AMR, pt:122
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#10: test AMR with NULL param (oa <-> null)
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
|
||||
#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:112
|
||||
conn[1]: codec:AMR, pt:122
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:112
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#11: test AMR with NULL param (bwe <-> null)
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 -> rc=0
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:AMR, pt:112
|
||||
conn[1]: codec:AMR, pt:122
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:AMR, pt:122
|
||||
conn[0]: codec:AMR, pt:112
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#12: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
|
@ -1374,14 +1544,16 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 97 GSM-HR-08/8000 -> rc=0
|
||||
1: 0 PCMU/8000 -> rc=0
|
||||
2: 96 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:PCMU, pt:0
|
||||
conn[1]: codec:PCMU, pt:0
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:GSM-HR-08, pt:97
|
||||
conn[0]: codec:GSM-HR-08, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#13: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
|
@ -1390,14 +1562,16 @@ Testing mgcp_codec_pt_translate()
|
|||
0: 97 GSM-HR-08 -> rc=0
|
||||
1: 0 PCMU -> rc=0
|
||||
2: 96 AMR octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
#10: test whether channel number matching is waterproof
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:PCMU, pt:0
|
||||
conn[1]: codec:PCMU, pt:0
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:GSM-HR-08, pt:97
|
||||
conn[0]: codec:GSM-HR-08, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
#14: test whether channel number matching is waterproof
|
||||
- add codecs on conn0:
|
||||
0: 111 GSM-HR-08/8000 -> rc=0
|
||||
1: 112 GSM-HR-08/8000/2 -> rc=-22
|
||||
|
@ -1405,10 +1579,15 @@ Testing mgcp_codec_pt_translate()
|
|||
- add codecs on conn1:
|
||||
0: 122 GSM-HR-08/8000/2 -> rc=-22
|
||||
1: 121 GSM-HR-08/8000/1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 121
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 113) -> -22
|
||||
- mgcp_codec_decide(&conn[0], &conn[1]):
|
||||
Codec decision result:
|
||||
conn[0]: codec:GSM-HR-08, pt:111
|
||||
conn[1]: codec:GSM-HR-08, pt:121
|
||||
- mgcp_codec_decide(&conn[1], &conn[0]):
|
||||
Codec decision result:
|
||||
conn[1]: codec:GSM-HR-08, pt:121
|
||||
conn[0]: codec:GSM-HR-08, pt:111
|
||||
===> SUCCESS: codec decision as expected!
|
||||
|
||||
Testing test_conn_id_matching
|
||||
needle='23AB' found '000023AB'
|
||||
|
|
|
@ -15,6 +15,7 @@ AM_CFLAGS = \
|
|||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
|
|
@ -73,7 +73,7 @@ static struct msgb *from_str(const char *str)
|
|||
return msg;
|
||||
}
|
||||
|
||||
static struct mgcp_client_conf conf;
|
||||
static struct mgcp_client_conf *conf;
|
||||
struct mgcp_client *mgcp = NULL;
|
||||
|
||||
static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
|
||||
|
@ -107,9 +107,6 @@ void test_response_cb(struct mgcp_response *response, void *priv)
|
|||
printf(" audio_port = %u\n", response->audio_port);
|
||||
printf(" audio_ip = %s\n", response->audio_ip);
|
||||
printf(" ptime = %u\n", response->ptime);
|
||||
printf(" codecs_len = %u\n", response->codecs_len);
|
||||
for(i=0;i<response->codecs_len;i++)
|
||||
printf(" codecs[%u] = %u\n", i, response->codecs[i]);
|
||||
printf(" ptmap_len = %u\n", response->ptmap_len);
|
||||
for(i=0;i<response->ptmap_len;i++) {
|
||||
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
|
||||
|
@ -149,12 +146,11 @@ void test_mgcp_msg(void)
|
|||
.conn_id = "11",
|
||||
.conn_mode = MGCP_CONN_RECV_SEND,
|
||||
.ptime = 20,
|
||||
.codecs[0] = CODEC_GSM_8000_1,
|
||||
.codecs[1] = CODEC_AMR_8000_1,
|
||||
.codecs[2] = CODEC_GSMEFR_8000_1,
|
||||
.codecs_len = 1,
|
||||
.ptmap[0].codec = CODEC_GSMEFR_8000_1,
|
||||
.ptmap[0].pt = 96,
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
|
||||
{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
|
||||
},
|
||||
.ptmap_len = 1,
|
||||
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
|
||||
.x_osmo_osmux_cid = -1, /* wildcard */
|
||||
|
@ -162,7 +158,7 @@ void test_mgcp_msg(void)
|
|||
|
||||
if (mgcp)
|
||||
talloc_free(mgcp);
|
||||
mgcp = mgcp_client_init(ctx, &conf);
|
||||
mgcp = mgcp_client_init(ctx, conf);
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
@ -179,9 +175,9 @@ void test_mgcp_msg(void)
|
|||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
||||
mgcp_msg.codecs_len = 2;
|
||||
mgcp_msg.ptmap_len = 2;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.ptmap_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated CRCX message (three codecs, one with custom pt):\n");
|
||||
|
@ -189,9 +185,9 @@ void test_mgcp_msg(void)
|
|||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
||||
mgcp_msg.codecs_len = 3;
|
||||
mgcp_msg.ptmap_len = 3;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.ptmap_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated MDCX message:\n");
|
||||
|
@ -209,9 +205,9 @@ void test_mgcp_msg(void)
|
|||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
mgcp_msg.codecs_len = 2;
|
||||
mgcp_msg.ptmap_len = 2;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.ptmap_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated MDCX message (three codecs, one with custom pt):\n");
|
||||
|
@ -220,9 +216,9 @@ void test_mgcp_msg(void)
|
|||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
mgcp_msg.codecs_len = 3;
|
||||
mgcp_msg.ptmap_len = 3;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.ptmap_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated DLCX message:\n");
|
||||
|
@ -315,7 +311,7 @@ void test_mgcp_msg(void)
|
|||
msgb_free(msg);
|
||||
}
|
||||
|
||||
void test_mgcp_client_cancel()
|
||||
void test_mgcp_client_cancel(void)
|
||||
{
|
||||
mgcp_trans_id_t trans_id;
|
||||
struct msgb *msg;
|
||||
|
@ -330,8 +326,10 @@ void test_mgcp_client_cancel()
|
|||
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
|
||||
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
|
||||
.ptime = 20,
|
||||
.codecs[0] = CODEC_AMR_8000_1,
|
||||
.codecs_len = 1
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
|
||||
},
|
||||
.ptmap_len = 1
|
||||
};
|
||||
|
||||
printf("\n%s():\n", __func__);
|
||||
|
@ -339,7 +337,7 @@ void test_mgcp_client_cancel()
|
|||
|
||||
if (mgcp)
|
||||
talloc_free(mgcp);
|
||||
mgcp = mgcp_client_init(ctx, &conf);
|
||||
mgcp = mgcp_client_init(ctx, conf);
|
||||
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
trans_id = mgcp_msg_trans_id(msg);
|
||||
|
@ -487,7 +485,7 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
|
|||
},
|
||||
};
|
||||
|
||||
void test_sdp_section_start()
|
||||
void test_sdp_section_start(void)
|
||||
{
|
||||
int i;
|
||||
int failures = 0;
|
||||
|
@ -531,7 +529,7 @@ void test_sdp_section_start()
|
|||
OSMO_ASSERT(!failures);
|
||||
}
|
||||
|
||||
static void test_map_pt_to_codec(void)
|
||||
static void test_map_str_to_codec(void)
|
||||
{
|
||||
/* Full form */
|
||||
OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
|
||||
|
@ -630,7 +628,7 @@ void test_mgcp_client_e1_epname(void)
|
|||
|
||||
if (mgcp)
|
||||
talloc_free(mgcp);
|
||||
mgcp = mgcp_client_init(ctx, &conf);
|
||||
mgcp = mgcp_client_init(ctx, conf);
|
||||
|
||||
/* Valid endpoint names */
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
|
||||
|
@ -675,6 +673,214 @@ void test_mgcp_client_e1_epname(void)
|
|||
OSMO_ASSERT(epname == NULL);
|
||||
}
|
||||
|
||||
struct parse_response_test {
|
||||
const char *body;
|
||||
int expect_rc;
|
||||
struct mgcp_response expect_params;
|
||||
};
|
||||
|
||||
static struct parse_response_test parse_response_tests[] = {
|
||||
{
|
||||
.body = "200 2 OK\r\n"
|
||||
"I: foo\r\n"
|
||||
"\r\n"
|
||||
"v=0\r\n"
|
||||
"o=- name 23 IN IP4 0.0.0.0\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 23 RTP/AVP 112 3\r\n" /* <-- implicit: 3 = GSM-FR */
|
||||
"a=rtpmap:112 AMR/8000\r\n"
|
||||
"a=ptime:20\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_params = {
|
||||
.audio_port = 23,
|
||||
.audio_ip = "1.2.3.4",
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 112 },
|
||||
{ .codec = CODEC_GSM_8000_1, .pt = 3 },
|
||||
},
|
||||
.ptmap_len = 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
.body = "200 2 OK\r\n"
|
||||
"I: foo\r\n"
|
||||
"\r\n"
|
||||
"v=0\r\n"
|
||||
"o=- name 23 IN IP4 0.0.0.0\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 23 RTP/AVP 112 3\r\n"
|
||||
"a=rtpmap:112 AMR/8000\r\n"
|
||||
"a=rtpmap:3 GSM/8000\r\n" /* 3 == GSM-FR implicitly, is an explicit entry a problem? */
|
||||
"a=ptime:20\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_params = {
|
||||
.audio_port = 23,
|
||||
.audio_ip = "1.2.3.4",
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 112 },
|
||||
{ .codec = CODEC_GSM_8000_1, .pt = 3 }, /* no, not a problem */
|
||||
},
|
||||
.ptmap_len = 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
.body = "200 2 OK\r\n"
|
||||
"I: foo\r\n"
|
||||
"\r\n"
|
||||
"v=0\r\n"
|
||||
"o=- name 23 IN IP4 0.0.0.0\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 23 RTP/AVP 3\r\n" /* <-- 112 is missing here. Will it still appear? */
|
||||
"a=rtpmap:112 AMR/8000\r\n"
|
||||
"a=ptime:20\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_params = {
|
||||
.audio_port = 23,
|
||||
.audio_ip = "1.2.3.4",
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_GSM_8000_1, .pt = 3 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 112 }, /* <-- yes, it was added to the end. */
|
||||
},
|
||||
.ptmap_len = 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* test MGCP_MAX_CODECS */
|
||||
.body = "200 2 OK\r\n"
|
||||
"I: foo\r\n"
|
||||
"\r\n"
|
||||
"v=0\r\n"
|
||||
"o=- name 23 IN IP4 0.0.0.0\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\n" /* <-- 10 codecs max */
|
||||
"a=rtpmap:101 AMR/8000\r\n"
|
||||
"a=rtpmap:102 AMR/8000\r\n"
|
||||
"a=rtpmap:103 AMR/8000\r\n"
|
||||
"a=rtpmap:104 AMR/8000\r\n"
|
||||
"a=rtpmap:105 AMR/8000\r\n"
|
||||
"a=rtpmap:106 AMR/8000\r\n"
|
||||
"a=rtpmap:107 AMR/8000\r\n"
|
||||
"a=rtpmap:108 AMR/8000\r\n"
|
||||
"a=rtpmap:109 AMR/8000\r\n"
|
||||
"a=rtpmap:110 AMR/8000\r\n"
|
||||
"a=ptime:20\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_params = {
|
||||
.audio_port = 23,
|
||||
.audio_ip = "1.2.3.4",
|
||||
.ptmap = {
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 101 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 102 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 103 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 104 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 105 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 106 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 107 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 108 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 109 },
|
||||
{ .codec = CODEC_AMR_8000_1, .pt = 110 },
|
||||
},
|
||||
.ptmap_len = 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* test MGCP_MAX_CODECS */
|
||||
.body = "200 2 OK\r\n"
|
||||
"I: foo\r\n"
|
||||
"\r\n"
|
||||
"v=0\r\n"
|
||||
"o=- name 23 IN IP4 0.0.0.0\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\n" /* <-- 11 > MGCP_MAX_CODECS */
|
||||
"a=rtpmap:101 AMR/8000\r\n"
|
||||
"a=rtpmap:102 AMR/8000\r\n"
|
||||
"a=rtpmap:103 AMR/8000\r\n"
|
||||
"a=rtpmap:104 AMR/8000\r\n"
|
||||
"a=rtpmap:105 AMR/8000\r\n"
|
||||
"a=rtpmap:106 AMR/8000\r\n"
|
||||
"a=rtpmap:107 AMR/8000\r\n"
|
||||
"a=rtpmap:108 AMR/8000\r\n"
|
||||
"a=rtpmap:109 AMR/8000\r\n"
|
||||
"a=rtpmap:110 AMR/8000\r\n"
|
||||
"a=ptime:20\r\n",
|
||||
.expect_rc = -EINVAL,
|
||||
},
|
||||
};
|
||||
|
||||
static void test_parse_response(void)
|
||||
{
|
||||
int i;
|
||||
int failures = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(parse_response_tests); i++) {
|
||||
int rc;
|
||||
struct parse_response_test *t = &parse_response_tests[i];
|
||||
struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
|
||||
int p;
|
||||
|
||||
r->body = talloc_strdup(r, t->body);
|
||||
|
||||
//printf("\n%s() test [%d]:\n", __func__, i);
|
||||
fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
|
||||
fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
|
||||
|
||||
rc = mgcp_response_parse_params(r);
|
||||
|
||||
fprintf(stderr, "got rc=%d\n", rc);
|
||||
if (rc != t->expect_rc) {
|
||||
fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
|
||||
failures++;
|
||||
}
|
||||
if (rc) {
|
||||
talloc_free(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
|
||||
if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
|
||||
fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
|
||||
failures++;
|
||||
}
|
||||
fprintf(stderr, "got audio_port=%u\n", r->audio_port);
|
||||
if (r->audio_port != t->expect_params.audio_port) {
|
||||
fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
|
||||
failures++;
|
||||
}
|
||||
|
||||
for (p = 0; p < r->ptmap_len; p++) {
|
||||
struct ptmap *got = &r->ptmap[p];
|
||||
struct ptmap *expect = NULL;
|
||||
fprintf(stderr, " %d %s\n", got->pt, osmo_mgcpc_codec_name(got->codec));
|
||||
if (p >= t->expect_params.ptmap_len) {
|
||||
fprintf(stderr, " - ERROR: too many codec entries\n");
|
||||
failures++;
|
||||
continue;
|
||||
}
|
||||
expect = &t->expect_params.ptmap[p];
|
||||
if (ptmap_cmp(got, expect)) {
|
||||
fprintf(stderr, " - ERROR: expected: %d %s\n",
|
||||
expect->pt, osmo_mgcpc_codec_name(expect->codec));
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(r);
|
||||
}
|
||||
|
||||
OSMO_ASSERT(!failures);
|
||||
}
|
||||
|
||||
|
||||
static const struct log_info_cat log_categories[] = {
|
||||
};
|
||||
|
||||
|
@ -697,15 +903,17 @@ int main(int argc, char **argv)
|
|||
|
||||
log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
|
||||
|
||||
mgcp_client_conf_init(&conf);
|
||||
conf = mgcp_client_conf_alloc(ctx);
|
||||
|
||||
test_mgcp_msg();
|
||||
test_mgcp_client_cancel();
|
||||
test_sdp_section_start();
|
||||
test_map_codec_to_pt_and_map_pt_to_codec();
|
||||
test_map_pt_to_codec();
|
||||
test_map_str_to_codec();
|
||||
test_mgcp_client_e1_epname();
|
||||
|
||||
test_parse_response();
|
||||
|
||||
printf("Done\n");
|
||||
fprintf(stderr, "Done\n");
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
|
||||
DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
|
||||
DLMGCP MGW(mgw) Message buffer too small, can not generate MGCP message (SDP)
|
||||
DLMGCP MGW(mgw) Failed to add SDP, can not generate MGCP message
|
||||
|
||||
test_mgcp_client_cancel():
|
||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
|
||||
|
@ -10,6 +11,7 @@ DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
|
|||
- cancel succeeds
|
||||
DLMGCP MGW(mgw) Canceled transaction 1
|
||||
- late response gets discarded
|
||||
DLMGCP MGW(mgw) MGCP link to MGW now considered UP
|
||||
DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
|
||||
DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
|
||||
- canceling again does nothing
|
||||
|
@ -135,4 +137,51 @@ DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw),
|
|||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
|
||||
|
||||
test_parse_response() test [0]:
|
||||
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
|
||||
got rc=0
|
||||
got audio_ip="1.2.3.4"
|
||||
got audio_port=23
|
||||
112 AMR/8000/1
|
||||
3 GSM/8000/1
|
||||
|
||||
test_parse_response() test [1]:
|
||||
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:3 GSM/8000\r\na=ptime:20\r\n"
|
||||
got rc=0
|
||||
got audio_ip="1.2.3.4"
|
||||
got audio_port=23
|
||||
112 AMR/8000/1
|
||||
3 GSM/8000/1
|
||||
|
||||
test_parse_response() test [2]:
|
||||
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
|
||||
DLMGCP error in MGCP message: 'a=rtpmap:112' has no matching entry in 'm=audio ... 112'
|
||||
got rc=0
|
||||
got audio_ip="1.2.3.4"
|
||||
got audio_port=23
|
||||
3 GSM/8000/1
|
||||
112 AMR/8000/1
|
||||
|
||||
test_parse_response() test [3]:
|
||||
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR/8"
|
||||
got rc=0
|
||||
got audio_ip="1.2.3.4"
|
||||
got audio_port=23
|
||||
101 AMR/8000/1
|
||||
102 AMR/8000/1
|
||||
103 AMR/8000/1
|
||||
104 AMR/8000/1
|
||||
105 AMR/8000/1
|
||||
106 AMR/8000/1
|
||||
107 AMR/8000/1
|
||||
108 AMR/8000/1
|
||||
109 AMR/8000/1
|
||||
110 AMR/8000/1
|
||||
|
||||
test_parse_response() test [4]:
|
||||
body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR"
|
||||
DLMGCP SDP: can parse only up to 10 payload type numbers
|
||||
DLMGCP Failed to parse SDP parameter payload types (RTP/AVP)
|
||||
got rc=-22
|
||||
Done
|
||||
|
|
Loading…
Reference in New Issue