Compare commits

..

6 Commits

Author SHA1 Message Date
Harald Welte
ba59fcf912 Convert RTP/RTCP/OSMUX I/O from osmo_fd to osmo_io
Converting from osmo_fd to osmo_io allows us to switch to the new
io_uring backend and benefit from related performance benefits.

In a benchmark running 200 concurrent bi-directional voice calls with
GSM-EFR codec, I am observing:

* the code before this patch uses 40..42% of a single core on a
  Ryzen 5950X at 200 calls (=> 200 endpoints with each two connections)

* no increase in CPU utilization before/after this patch, i.e. the
  osmo_io overhead for the osmo_fd backend is insignificant compared
  to the direct osmo_fd mode before

* an almost exactly 50% reduction of CPU utilization when running the
  same osmo-mgw build with LIBOSMO_IO_BACKEND=IO_URING - top shows
  19..21% for the same workload instead of 40..42% with the OSMO_FD
  default backend.

* An increase of about 4 Megabytes in both RSS and VIRT size when
  enabling the OSMO_IO backend.  This is likely the memory-mapped rings.

No memory leakage is observed when using either of the backends.

Change-Id: I8471960d5d8088a70cf105f2f40dfa5d5458169a
2024-03-20 12:43:42 +01:00
Harald Welte
0188aad11c Change msgb ownership in processing of received msgb
The old approach was: rtp_data_net() reads a msgb from the incomging
socket, calls through whatever function chain and in the end free's it.
So none of the intermediate functions was permitted to take msgb
ownership.

This was a good choice as all processing would happen synchronously,
up to the point where that msgb was written on the output RTP socket.

Let's change this from passing msgb ownership throug the whole call
chain, through rx_rtp() to the various *_dispatch_rtp() functions.

This is required for upcoming migration to osmo_io, as in that case the
write (sendto) calls are asynchronous and hence msgb ownership needs
to be transferred.

Change-Id: I6a331f3c6b2eb51ea312ac6ef8c357185ddb79cf
2024-03-20 12:43:40 +01:00
Harald Welte
1ce53ac6a9 remove osmo_fd from mgcp_create_bind()
preparation for osmo_io

Change-Id: I4a3b66a14fdfbc867daca0f0a05f694d5e0d7b66
2024-03-20 12:36:21 +01:00
Harald Welte
179525e07b don't log useless "transcoding disabled" message
The entire mgw has no transcoding support.  So printing that message is
useless to begin with.  And printing it for *every RTP packet* is even
more useless.  Let's remove it.

Change-Id: If0ee2607404afc3a00665a5cf22a9e0eb62eb476
2024-03-19 18:31:48 +01:00
Harald Welte
f12ad38d46 simplify unused transcoding/processing call-back
the processing call-back is working with a raw buffer + length,
while we actually work with struct msgb.  Let's simply pass the msgb
into the call-back, and the call-back can then do what they want with
the contents of that msgb.

Change-Id: I002624f9008726e3d754d48aa2282c38e3b42953
2024-03-19 18:29:02 +01:00
Harald Welte
dd25ba52bd remove strange loop for non-existant transcoding support
The existing support preparing the mgw for transcoding (which doesn't exist)
has some kind of method where the transcoding function might be called
multiple times in a row.  However, as it is not used, it is not entirely
clear how it was intended to work.  Let's remove this unused looping
feature which makes it hard to understand how upcoming osmo_io should
deal with it.

Change-Id: Ie1a629fd31c5ab806fc929d1e6b279c4be5b8246
2024-03-19 18:24:23 +01:00
43 changed files with 1488 additions and 1924 deletions

View File

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

View File

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

View File

@@ -44,13 +44,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.11.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.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 -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
@@ -204,4 +204,5 @@ AC_OUTPUT(
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-mgw.spec
Makefile)

View File

@@ -22,7 +22,7 @@ export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" --disable-doxygen
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
@@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
export PATH="$inst/bin:$PATH"
osmo-build-dep.sh libosmo-netif "" --disable-doxygen
osmo-build-dep.sh libosmo-abis
osmo-build-dep.sh libosmo-netif
# Additional configure options and depends
CONFIG=""

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

@@ -0,0 +1,122 @@
#
# 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.4.0
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
BuildRequires: pkgconfig(libosmocoding) >= 1.9.0
BuildRequires: pkgconfig(libosmoabis) >= 1.5.0
BuildRequires: pkgconfig(libosmotrau) >= 1.5.0
%{?systemd_requires}
%description
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
%package -n libosmo-mgcp-client12
Summary: Osmocom's Media Gateway Control Protocol client library
Group: System/Libraries
%description -n libosmo-mgcp-client12
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-client12 = %{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.
%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-client12 -p /sbin/ldconfig
%postun -n libosmo-mgcp-client12 -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.md
%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-client12
%{_libdir}/libosmo-mgcp-client.so.12*
%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
%changelog

View File

@@ -9,11 +9,8 @@ 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):

140
debian/changelog vendored
View File

@@ -1,143 +1,3 @@
osmo-mgw (1.14.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* jenkins.sh: libosmo-netif no longer depends on libosmo-abis
* jenkins.sh: Use --disable-doxygen configure param
* mgcp-client: Fix wrong value passed to strerror()
* mgcp_client_internal.h: Add missing header dependency
* mgcp-cli: Mark iofd ptr as NULL when freed
* mgcp-cli: Improve error handling around mgcp_msg_gen() return
* mgcp-cli: Fix filling in wrong local IP address of SDP Origin o=
* mgw: Drop own MGCP extension 'noanswer'
* cosmetic: mgw: Fix indentation whitespace
* mgcp-client: Fix regression checking null ptr
* mgw: Rename and move code freeing endp connection
* mgw: Rename and move several get_conn funcs acting on endp object
* mgw: mgcp_network.c: Simplify use of conn_rtp ptr
* mgw: Clean up access to conn_rtp from conn
* mgw: Avoid 2nd lookup of conn in endp during CRCX
* cosmetic: mgw: iuup: Update comment
* mgw: constify mgcp_endp_avail() param
* mgcp_endp: Add helpers accessing endp connections
* mgw: mgcp_protocol: assert freeing last conn allows creating new conn
* mgw: Split conn mode parsing and applying into conn
* mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables
* mgw: Use bool instead of int in local var
* Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port()
* mgw: Split mgcp_rtp_end to its own file
* mgw: Introduce mgcp_rtp_end_init()
* mgw: Introduce struct mgcp_codecset struct
* mgw: Cleanup rtp_endp fields in its own function
* mgw: Move force_ptime logic outside of main CRCX func handler
* mgw: Move several params setting to mgcp_rtp_end_init()
* mgw: Simplify and redo code around ssrc patch feature
* mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
* mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
* mgw: CRCX: Split mgcp header pars parsing into a previous step
* mgw: MDCX: Split mgcp header pars parsing into a previous step
* mgw: DLCX: Split mgcp header pars parsing into a previous step
* mgw: Decouple SDP parsing step from conn obj update
* mgw: Remove wrong TODO comment
* mgw: MDCX: Simplify early return code paths
[ Mychaela N. Falconia ]
* E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
* E1: replace idle_tf_efr[] with a better version
* E1: replace idle_tf_fr[] with a better version
-- Oliver Smith <osmith@sysmocom.de> Wed, 12 Feb 2025 12:30:33 +0100
osmo-mgw (1.13.1) unstable; urgency=medium
[ Philipp Maier ]
* mgcp_network: use an uint16_t to store the port number
* mgcp_network: add missing ntohs
[ Pau Espin Pedrol ]
* tests/mgcp/mgcp_test: Add some extra asserts in code
-- Oliver Smith <osmith@sysmocom.de> Thu, 12 Sep 2024 13:53:19 +0200
osmo-mgw (1.13.0) unstable; urgency=medium
[ Neels Hofmeyr ]
* add mgcp_conn_rtp_type_names[]
* mgcp_parse_audio_port_pt(): fix buffer overflow
* client: replace two assertions with graceful error handling
* systemd,manual: set LimitNOFILE=65536
* IuUP: allow Initialization from any address if not yet set
* check_rtp_origin: drop special case for legacy IuUP hack
* mgcp_client_test: fix function name
* fix possible NULL deref on early media
* client: move some items to internal header
* client: safely handle dealloc on event dispatch
* build: move mgcp/*.h to noinst_HEADERS, drop RPM libosmo-mgcp-devel
* client: deprecate legacy API
* client: collapse codecs[] and ptmap[]; allow codec variants
* client: allow MGCP_MAX_CODECS entries
* client SDP: more verbose error logging
* mgcp_client_test: add test_parse_response()
* drop (now) unused code
* tests/mgcp: add update_exp target
* drop get_net_downlink_format_cb
* drop cfg 'sdp audio fmtp-extra'
* mgcp_codec_decide: remove redundant lookup
* tweak DEBUG log
* mgcp_test: fix false negatives in test output
* mgw: do not fail MGCP on codec mismatch
* mgcp-client: always send 'm=audio' line
* mgcp_test.c: verify osmo-mgw accepts m=audio 0
* mgcp_test.c: fix various missing '\r' and '\n'
* mgcp_test: test a=ptime:20, not 40
* mgcp_test: add CRCX for IUFP in sendrecv
* do not FAIL on CRCX in sendrecv mode
[ Keith Whyte ]
* vty and log: also show local port for RTP conns
[ Andreas Eversberg ]
* Use uniform log format for default config files
[ Pau Espin Pedrol ]
* mgcp_network: Improve err logging when rtp pkt from unexpected origin comes in
* cosmetic: Fix line indentation
* IuUP: Allow Initialization with set rem IP address and unset rem port
* mgcp-client: Transmit remote IP addr in CRCX if known and port=0
* Fix IuUP RTP hdr seqnr field not incremented
* iuup: Increment RTP hdr seqnr even if Tx over UDP fails
[ Vadim Yanitskiy ]
* mgcp: simplify getting msgb tail in mgcp_msg_terminate_nul()
* mgcp: reserve once byte for '\0' in mgcp_do_read()
* mgcp: correctly put NUL character in mgcp_msg_terminate_nul()
* build: include README into the release tarball
[ neels ]
* Revert "drop (now) unused code"
[ Harald Welte ]
* Convert README to README.md and expand like in other projects
* migrate mgcp_client from osmo_wqueue to osmo_io
* mgw: Add our usual SIGABRT, SIGUSR1 signal handlers
* don't log useless "transcoding disabled" message
* remove strange loop for non-existant transcoding support
* simplify unused transcoding/processing call-back
* remove osmo_fd from mgcp_create_bind()
* Change msgb ownership in processing of received msgb
* cosmetic: make linter happy
* Convert RTP/RTCP/OSMUX I/O from osmo_fd to osmo_io
[ Oliver Smith ]
* contrib: remove rpm spec file
* contrib/systemd: run as osmocom user
* doc: example configs: fix deprecation warnings
[ Mychaela N. Falconia ]
* E1: support HRv1 codec on both 16k and 8k subslots
* fix E1 TS output when used with osmo-e1d
-- Oliver Smith <osmith@sysmocom.de> Wed, 24 Jul 2024 15:44:47 +0200
osmo-mgw (1.12.1) unstable; urgency=medium
[ Pau Espin Pedrol ]

12
debian/control vendored
View File

@@ -6,10 +6,10 @@ Build-Depends: debhelper (>= 10),
dh-autoreconf,
pkg-config,
autotools-dev,
libosmocore-dev (>= 1.11.0),
libosmo-netif-dev (>= 1.6.0),
libosmo-abis-dev (>= 2.0.0),
osmo-gsm-manuals-dev (>= 1.6.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-client14
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-client14 (= ${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

38
debian/postinst vendored
View File

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

View File

@@ -14,12 +14,15 @@ e1_input
e1_line 0 port 0
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16001
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 512
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc

View File

@@ -11,12 +11,15 @@ log stderr
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16001
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 512
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc

View File

@@ -1,7 +1,6 @@
noinst_HEADERS = \
vty.h \
mgcp_msg.h \
mgcp_codec.h \
mgcp_conn.h \
mgcp_stat.h \
mgcp_endp.h \
@@ -14,5 +13,4 @@ noinst_HEADERS = \
mgcp_network.h \
mgcp_protocol.h \
mgcp_iuup.h \
mgcp_rtp_end.h \
$(NULL)

View File

@@ -1,9 +1,5 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/mgcp/mgcp_common.h>
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
@@ -12,37 +8,14 @@
#define PTYPE_UNDEFINED (-1)
struct mgcp_rtp_codec {
uint32_t rate;
int channels;
uint32_t frame_duration_num;
uint32_t frame_duration_den;
int payload_type;
char audio_name[64];
char subtype_name[64];
bool param_present;
struct mgcp_codec_param param;
};
struct mgcp_conn_rtp;
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
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_codecset {
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
/* array with assigned audio codecs to choose from (SDP) */
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
/* number of assigned audio codecs (SDP) */
unsigned int codecs_assigned;
};
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
const char *subtype_name, unsigned int match_nr);
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type);

View File

@@ -24,14 +24,11 @@
#pragma once
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_network.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/iuup.h>
#include <osmocom/mgcp/mgcp_rtp_end.h>
#include <inttypes.h>
#define LOGPCONN(conn, cat, level, fmt, args...) \
@@ -240,16 +237,15 @@ static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
return conn->type == MGCP_RTP_IUUP;
}
static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn)
{
OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
return &conn->u.rtp;
}
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
enum mgcp_conn_type type, char *name);
void mgcp_conn_free(struct mgcp_conn *conn);
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode);
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
const char *id);
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
char *mgcp_conn_dump(struct mgcp_conn *conn);
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);

View File

@@ -138,20 +138,11 @@ 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,
struct mgcp_config *cfg);
bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
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);
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
const char *id);

View File

@@ -27,8 +27,6 @@
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/mgcp/mgcp_common.h>
struct mgcp_conn;
struct mgcp_parse_data;
struct mgcp_endpoint;
@@ -36,14 +34,14 @@ struct mgcp_trunk;
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg);
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
struct mgcp_conn *conn);
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata);
int mgcp_parse_osmux_cid(const char *line);
bool mgcp_check_param(const char *line);
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);

View File

@@ -74,6 +74,65 @@ struct mgcp_rtp_state {
uint32_t alt_rtp_tx_ssrc;
};
struct mgcp_rtp_codec {
uint32_t rate;
int channels;
uint32_t frame_duration_num;
uint32_t frame_duration_den;
int payload_type;
char audio_name[64];
char subtype_name[64];
bool param_present;
struct mgcp_codec_param param;
};
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
/* remote IP address of the RTP socket */
struct osmo_sockaddr addr;
/* in network byte order */
int rtcp_port;
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
/* array with assigned audio codecs to choose from (SDP) */
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
/* number of assigned audio codecs (SDP) */
unsigned int codecs_assigned;
/* per endpoint data */
int frames_per_packet;
uint32_t packet_duration_ms;
int maximum_packet_time; /* -1: not set */
/* are we transmitting packets (true) or dropping (false) outbound packets */
bool output_enabled;
/* FIXME: This parameter can be set + printed, but is nowhere used! */
int force_output_ptime;
/* RTP patching */
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
int force_aligned_timing;
bool rfc5993_hr_convert;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_io_fd *rtp;
struct osmo_io_fd *rtcp;
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
/* where the endpoint RTP connection binds to, set during CRCX and
* possibly updated during MDCX */
char local_addr[INET6_ADDRSTRLEN];
};
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
struct mgcp_rtp_tap {
/* is this tap active (1) or not (0) */
int enabled;
@@ -91,7 +150,9 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn);
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,

View File

@@ -1,73 +1,11 @@
#pragma once
#include <stdint.h>
#include <sys/socket.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_codec.h>
#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
#define MGCP_PARSE_SDP_RTP_PORT_UNSET (0)
struct mgcp_parse_sdp {
int ptime;
int maxptime;
int rtp_port;
struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */
struct mgcp_rtp_codecset cset;
};
static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
{
sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET;
sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET;
sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET;
sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC };
mgcp_codecset_reset(&sdp->cset);
}
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2)
#define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1)
struct mgcp_parse_hdr_pars {
const char *local_options;
const char *callid;
const char *connid;
enum mgcp_connection_mode mode;
int remote_osmux_cid;
bool have_sdp;
/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
uint32_t x_osmo_ign;
};
static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
{
*hpars = (struct mgcp_parse_hdr_pars){
.local_options = NULL,
.callid = NULL,
.connid = NULL,
.mode = MGCP_CONN_NONE,
.remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET,
.have_sdp = false,
.x_osmo_ign = 0,
};
}
/* Internal structure while parsing a request */
struct mgcp_parse_data {
struct mgcp_config *cfg;
char *save;
/* MGCP Header: */
char *epname;
char *trans;
struct mgcp_parse_hdr_pars hpars;
/* MGCP Body: */
struct mgcp_parse_sdp sdp;
char *save;
};
/* Local connection options */
@@ -85,12 +23,8 @@ int check_local_cx_options(void *ctx, const char *options);
struct mgcp_rtp_end;
struct mgcp_endpoint;
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
struct mgcp_rtp_end *rtp);
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
const struct mgcp_rtp_end *rtp);
extern const struct value_string mgcp_connection_mode_strs[];
static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
{
return get_value_string(mgcp_connection_mode_strs, mode);
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_codec.h>
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
struct mgcp_conn_rtp *conn_rtp; /* backpointer */
/* remote IP address of the RTP socket */
struct osmo_sockaddr addr;
/* in network byte order */
uint16_t rtcp_port;
struct mgcp_rtp_codecset cset;
/* per endpoint data */
int frames_per_packet;
uint32_t packet_duration_ms;
int maximum_packet_time; /* -1: not set */
/* are we transmitting packets (true) or dropping (false) outbound packets */
bool output_enabled;
/* FIXME: This parameter can be set + printed, but is nowhere used! */
int force_output_ptime;
/* RTP patching */
bool force_constant_ssrc;
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
int force_aligned_timing;
bool rfc5993_hr_convert;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_io_fd *rtp;
struct osmo_io_fd *rtcp;
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
/* where the endpoint RTP connection binds to, set during CRCX and
* possibly updated during MDCX */
char local_addr[INET6_ADDRSTRLEN];
};
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp);
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end);
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms);
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end);

View File

@@ -22,9 +22,9 @@
#pragma once
struct mgcp_parse_data;
int mgcp_parse_sdp_data(struct mgcp_parse_data *p);
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn,
struct mgcp_parse_data *p);
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
const struct mgcp_conn_rtp *conn, struct msgb *sdp,

View File

@@ -2,10 +2,9 @@
#include <osmocom/gsm/i460_mux.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_network.h>
#include <osmocom/mgcp/mgcp_ratectr.h>
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
LOGP(cat, level, "trunk:%u " fmt, \
trunk ? trunk->trunk_nr : 0, \
@@ -35,7 +34,7 @@ struct mgcp_trunk {
int keepalive_interval;
/* RTP patching */
bool force_constant_ssrc;
int force_constant_ssrc; /* 0: don't, 1: once */
int force_aligned_timing;
bool rfc5993_hr_convert;
@@ -79,7 +78,6 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp);
/* The virtual trunk is always created on trunk id 0 for historical reasons,
* use this define constant as ID when allocating a virtual trunk. Other

View File

@@ -3,8 +3,6 @@
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/timer.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#define MSGB_CB_MGCP_TRANS_ID 0
/* Struct that holds one endpoint name */

View File

@@ -19,7 +19,7 @@ AM_LDFLAGS = \
# This is not at all related to the release version, but a range of supported
# API versions. Read TODO_RELEASE in the source tree's root!
MGCP_CLIENT_LIBVERSION=14:1:0
MGCP_CLIENT_LIBVERSION=13:0:1
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \

View File

@@ -786,10 +786,8 @@ static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
if (res <= 0) {
char errbuf[128] = "";
strerror_r(-res, errbuf, sizeof(errbuf));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
osmo_iofd_get_name(iofd), res, errbuf);
osmo_iofd_get_name(iofd), res, strerror(res));
msgb_free(msg);
return;
@@ -824,10 +822,8 @@ static void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
if (OSMO_UNLIKELY(res != msg->len)) {
char errbuf[128] = "";
strerror_r(-res, errbuf, sizeof(errbuf));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
osmo_iofd_get_name(mgcp->iofd), res, errbuf,
osmo_iofd_get_name(mgcp->iofd), res, strerror(res),
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
}
}
@@ -864,10 +860,6 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
};
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
if (!msgb_dlcx) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname);
return;
}
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
}
@@ -881,10 +873,6 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
};
OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
if (!msgb_auep) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname);
return;
}
mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
}
@@ -1059,7 +1047,6 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
osmo_iofd_txqueue_clear(mgcp->iofd);
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd));
osmo_iofd_free(mgcp->iofd);
mgcp->iofd = NULL;
}
/*! Get the IP-Aaddress of the associated MGW as string.
@@ -1320,36 +1307,6 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
#undef MSGB_PRINTF_OR_RET
}
/* Helper function to obtain local IP address used in MGCP towards MGW,
* in string format, to fill the SDP "Origin" ("o=") field.
* return 0 on success, negative on error.
*/
static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len)
{
int fd;
/* Try to get the socket local IP address if available: */
if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) {
if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0)
return 0;
/* else: continue below */
}
/* If MGCP local address was explicitly specified in config, use it: */
if (mgcp->actual.local_addr) {
osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len);
return 0;
}
/* Guess our local address based on system routing towards MGW: */
OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN);
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0)
return 0;
LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n");
return -EINVAL;
}
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
{
@@ -1358,8 +1315,6 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
int local_ip_family, audio_ip_family;
const char *codec;
unsigned int pt;
uint16_t audio_port;
int rc;
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
@@ -1375,9 +1330,11 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
MSGB_PRINTF_OR_RET("v=0\r\n");
/* Determine local IP-Address */
rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip));
if (rc < 0)
return rc;
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
LOGPMGW(mgcp, LOGL_ERROR,
"Could not determine local IP-Address!\n");
return -EINVAL;
}
local_ip_family = osmo_ip_str_type(local_ip);
if (local_ip_family == AF_UNSPEC)
return -EINVAL;
@@ -1409,19 +1366,17 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
MSGB_PRINTF_OR_RET("t=0 0\r\n");
/* Add RTP address port and codecs */
audio_port = 0;
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)) {
audio_port = mgcp_msg->audio_port;
if (!audio_port) {
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT) {
if (mgcp_msg->audio_port == 0) {
LOGPMGW(mgcp, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
return -EINVAL;
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
for (i = 0; i < mgcp_msg->ptmap_len; i++)
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
MSGB_PRINTF_OR_RET("\r\n");
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", audio_port);
for (i = 0; i < mgcp_msg->ptmap_len; i++)
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
MSGB_PRINTF_OR_RET("\r\n");
/* Add optional codec parameters (fmtp) */
if (mgcp_msg->param_present) {

View File

@@ -157,7 +157,6 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
mgcp_msg->conn_mode = conn_mode;
}
/* returns message buffer containing MGXP MDCX on success, NULL on error. */
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
{
struct mgcp_msg mgcp_msg;
@@ -193,7 +192,6 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
}
/* returns message buffer containing MGXP DLCX on success, NULL on error. */
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
{
struct mgcp_msg mgcp_msg;
@@ -233,10 +231,8 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
if (!msg) {
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
return;
}
OSMO_ASSERT(msg);
mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
mgcp_ctx->mgw_trans_pending = true;
rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);

View File

@@ -40,7 +40,6 @@ libosmo_mgcp_a_SOURCES = \
mgcp_endp.c \
mgcp_trunk.c \
mgcp_ratectr.c \
mgcp_rtp_end.c \
mgcp_e1.c \
mgcp_iuup.c \
$(NULL)

View File

@@ -28,7 +28,7 @@
/* Helper function to dump codec information of a specified codec to a printable
* string, used by dump_codec_summary() */
static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
static char *dump_codec(struct mgcp_rtp_codec *codec)
{
static char str[256];
char *pt_str;
@@ -49,25 +49,31 @@ static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
}
/*! Dump a summary of all negotiated codecs to debug log
* \param[in] cset related codecset.
* \param[in] prefix_str Prefix string to print during logging.
* */
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
* \param[in] conn related rtp-connection. */
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_end *rtp;
unsigned int i;
struct mgcp_rtp_codec *codec;
struct mgcp_endpoint *endp;
if (cset->codecs_assigned == 0) {
LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
rtp = &conn->end;
endp = conn->conn->endp;
if (rtp->codecs_assigned == 0) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
mgcp_conn_dump(conn->conn));
return;
}
/* Store parsed codec information */
for (i = 0; i < cset->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec = &cset->codecs[i];
for (i = 0; i < rtp->codecs_assigned; i++) {
codec = &rtp->codecs[i];
LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
if (codec == cset->codec)
if (codec == rtp->codec)
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
LOGPC(DLMGCP, LOGL_DEBUG, "\n");
@@ -75,7 +81,7 @@ void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_st
}
/* Initalize or reset codec information with default data. */
static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
static void codec_init(struct mgcp_rtp_codec *codec)
{
*codec = (struct mgcp_rtp_codec){
.payload_type = -1,
@@ -88,20 +94,20 @@ static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
};
}
static void mgcp_codec_free(struct mgcp_rtp_codec *codec)
static void codec_free(struct mgcp_rtp_codec *codec)
{
*codec = (struct mgcp_rtp_codec){};
}
/*! Initalize or reset codec information with default data.
* \param[out] conn related rtp-connection. */
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
{
int i;
for (i = 0; i < cset->codecs_assigned; i++)
mgcp_codec_free(&cset->codecs[i]);
cset->codecs_assigned = 0;
cset->codec = NULL;
for (i = 0; i < conn->end.codecs_assigned; i++)
codec_free(&conn->end.codecs[i]);
conn->end.codecs_assigned = 0;
conn->end.codec = NULL;
}
/*! Add codec configuration depending on payload type and/or codec name. This
@@ -112,23 +118,23 @@ void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
* \param[in] param optional codec parameters (set to NULL when unused).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
{
int rate;
int channels;
struct mgcp_rtp_codec *codec;
unsigned int pt_offset = cset->codecs_assigned;
unsigned int pt_offset = conn->end.codecs_assigned;
/* The amount of codecs we can store is limited, make sure we do not
* overrun this limit. */
if (cset->codecs_assigned >= MGCP_MAX_CODECS)
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
return -EINVAL;
/* First unused entry */
codec = &cset->codecs[cset->codecs_assigned];
codec = &conn->end.codecs[conn->end.codecs_assigned];
/* Initalize the codec struct with some default data to begin with */
mgcp_codec_init(codec);
codec_init(codec);
if (payload_type != PTYPE_UNDEFINED) {
/* Make sure we do not get any reserved or undefined type numbers */
@@ -262,11 +268,11 @@ int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, co
} else
codec->param_present = false;
cset->codecs_assigned++;
conn->end.codecs_assigned++;
return 0;
error:
/* Make sure we leave a clean codec entry on error. */
mgcp_codec_free(codec);
codec_free(codec);
return -EINVAL;
}
@@ -290,7 +296,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
}
/* Compare two codecs, all parameters must match up */
static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
* exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
@@ -319,7 +325,7 @@ static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_
}
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
* translate between different payload formats as long as the encoded voice data itself does not change.
@@ -348,18 +354,21 @@ iufp:
return true;
}
struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int codecs_assigned;
rtp_end = &conn->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codecs_assigned = cset->codecs_assigned;
codecs_assigned = rtp_end->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_same(codec, &cset->codecs[i])) {
return &cset->codecs[i];
if (codecs_same(codec, &rtp_end->codecs[i])) {
return &rtp_end->codecs[i];
break;
}
}
@@ -368,26 +377,28 @@ struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, c
}
/* For a given codec, find a convertible codec in the given connection. */
static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int 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_codecset_find_same(cset, codec);
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 = cset->codecs_assigned;
codecs_assigned = rtp_end->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_convertible(codec, &cset->codecs[i])) {
codec_convertible = &cset->codecs[i];
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
codec_convertible = &rtp_end->codecs[i];
break;
}
}
@@ -397,20 +408,20 @@ static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
* a tentative decision is made.
* \param[in] cset_src related codec set.
* \param[inout] cset_dst related destination codec set (NULL if not present).
* \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_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
{
unsigned int i;
/* 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(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
if (!cset_dst || cset_dst->codecs_assigned == 0) {
if (cset_src->codecs_assigned >= 1) {
cset_src->codec = &cset_src->codecs[0];
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;
@@ -419,38 +430,38 @@ int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_cod
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
* 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 < cset_src->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
if (codec_cset_dst) {
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. */
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
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 < cset_src->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
if (codec_cset_dst) {
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. */
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
return 0;
}
}
if (cset_dst->codecs_assigned)
cset_dst->codec = &cset_dst->codecs[0];
if (conn_dst->end.codecs_assigned)
conn_dst->end.codec = &conn_dst->end.codecs[0];
else
return -EINVAL;
if (cset_src->codecs_assigned)
cset_src->codec = &cset_src->codecs[0];
if (conn_src->end.codecs_assigned)
conn_src->end.codec = &conn_src->end.codecs[0];
else
return -EINVAL;
@@ -477,36 +488,38 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
* with incrementing match_nr.
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr)
{
int i;
for (i = 0; i < cset->codecs_assigned; i++) {
if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
for (i = 0; i < conn->end.codecs_assigned; i++) {
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
if (match_nr) {
match_nr--;
continue;
}
return &cset->codecs[i];
return &conn->end.codecs[i];
}
}
return NULL;
}
/*! Lookup a codec that is assigned to a connection by its payload type number.
* \param[in] cset related codec set.
* \param[in] conn related rtp-connection.
* \param[in] payload_type number of the codec to look up.
* \returns pointer to codec struct on success, NULL on failure. */
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
{
struct mgcp_rtp_end *rtp_end = &conn->end;
unsigned int codecs_assigned = rtp_end->codecs_assigned;
struct mgcp_rtp_codec *codec = NULL;
size_t i;
OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < cset->codecs_assigned; i++) {
if (payload_type == cset->codecs[i].payload_type) {
codec = &cset->codecs[i];
for (i = 0; i < codecs_assigned; i++) {
if (payload_type == rtp_end->codecs[i].payload_type) {
codec = &rtp_end->codecs[i];
break;
}
}

View File

@@ -74,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
/* ensure that the generated conn_id is unique
* for this endpoint */
if (!mgcp_endp_get_conn_rtp(endp, id_hex)) {
if (!mgcp_conn_get_rtp(endp, id_hex)) {
osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
return 0;
}
@@ -88,6 +88,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
/* Initialize rtp connection struct with default values */
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
{
struct mgcp_rtp_end *end = &conn_rtp->end;
/* FIXME: Each new rate counter group requires an unique index. At the
* moment we generate this index using this counter, but perhaps there
* is a more concious way to assign the indexes. */
@@ -105,6 +106,17 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
/* backpointer to the generic part of the connection */
conn->u.rtp.conn = conn;
end->rtp = NULL;
end->rtcp = NULL;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;
/* Set default values */
end->frames_per_packet = 0; /* unknown */
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = false;
end->maximum_packet_time = -1;
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
if (!conn_rtp->ctrg)
return -1;
@@ -112,7 +124,9 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
/* Make sure codec table is reset */
mgcp_codec_reset_all(conn_rtp);
return 0;
}
@@ -123,15 +137,16 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
conn_osmux_disable(conn_rtp);
if (mgcp_conn_rtp_is_iuup(conn_rtp))
mgcp_conn_iuup_cleanup(conn_rtp);
mgcp_rtp_end_cleanup(&conn_rtp->end);
mgcp_free_rtp_port(&conn_rtp->end);
rate_ctr_group_free(conn_rtp->ctrg);
mgcp_codec_reset_all(conn_rtp);
}
void mgcp_conn_watchdog_cb(void *data)
{
struct mgcp_conn *conn = data;
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
mgcp_conn_free(conn);
mgcp_conn_free(conn->endp, conn->id);
}
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
@@ -197,6 +212,58 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
return conn;
}
/*! find a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
{
struct mgcp_conn *conn;
const char *id_upper;
const char *conn_id;
if (!id || !*id)
return NULL;
/* Ignore leading zeros in needle */
while (*id == '0')
id++;
/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
* Connections" defines the id as a hex string, so clients may return lower case hex even though
* we sent upper case hex in the CRCX response. */
id_upper = osmo_str_toupper(id);
llist_for_each_entry(conn, &endp->conns, entry) {
/* Ignore leading zeros in haystack */
for (conn_id=conn->id; *conn_id == '0'; conn_id++);
if (strcmp(conn_id, id_upper) == 0)
return conn;
}
return NULL;
}
/*! find an RTP connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
const char *id)
{
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
if (!conn)
return NULL;
if (conn->type == MGCP_CONN_TYPE_RTP)
return &conn->u.rtp;
return NULL;
}
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
{
struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
@@ -219,21 +286,21 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
}
/*! free a connection
* \param[in] conn the conn to free. May be NULL.
*/
void mgcp_conn_free(struct mgcp_conn *conn)
/*! free a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection */
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
{
struct mgcp_conn_rtp *conn_rtp;
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
if (!conn)
return;
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
conn_rtp = mgcp_conn_get_conn_rtp(conn);
aggregate_rtp_conn_stats(conn->endp, conn_rtp);
mgcp_rtp_conn_cleanup(conn_rtp);
aggregate_rtp_conn_stats(endp, &conn->u.rtp);
mgcp_rtp_conn_cleanup(&conn->u.rtp);
break;
default:
/* NOTE: This should never be called with an
@@ -243,40 +310,43 @@ void mgcp_conn_free(struct mgcp_conn *conn)
}
osmo_timer_del(&conn->watchdog);
mgcp_endp_remove_conn(conn->endp, conn);
mgcp_endp_remove_conn(endp, conn);
/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
talloc_free(conn);
}
/*! Parse connection mode.
* \param[in] conn Connection whose mode is being set
* \param[in] mode Mode to set
* \returns 0 on success, -1 on error */
int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode)
/*! free oldest connection in the list.
* \param[in] endp associated endpoint */
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
{
OSMO_ASSERT(conn);
if (mode == MGCP_CONN_NONE) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"missing connection mode\n");
return -1;
}
conn->mode = mode;
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
mgcp_cmode_name(mode), conn->mode);
struct mgcp_conn *conn;
/* Special handling for RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
conn_rtp->end.output_enabled);
}
if (llist_empty(&endp->conns))
return;
/* The VTY might change the connection mode at any time, so we have
* to hold a copy of the original connection mode */
conn->mode_orig = conn->mode;
conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
if (!conn)
return;
return 0;
mgcp_conn_free(endp, conn->id);
}
/*! free all connections at once.
* \param[in] endp associated endpoint */
#if defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
#endif
#endif
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
/* Drop all items in the list, might be consecutive! */
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
mgcp_conn_free(endp, conn->id);
return;
}
/*! dump basic connection information to human readable string.
@@ -287,26 +357,24 @@ 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) };
struct mgcp_conn_rtp *conn_rtp;
if (!conn)
return "NULL";
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
conn_rtp = mgcp_conn_get_conn_rtp(conn);
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_rtp->end.addr.u.sa, ipbuf) ? : "NULL",
osmo_sockaddr_port(&conn_rtp->end.addr.u.sa),
conn_rtp->end.local_addr ? : "NULL",
conn_rtp->end.local_port);
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_rtp->type) {
switch (conn->u.rtp.type) {
case MGCP_RTP_OSMUX:
OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_rtp->osmux.local_cid);
OSMO_STRBUF_PRINTF(sb, " CID=%u", conn->u.rtp.osmux.local_cid);
break;
default:
break;
@@ -346,6 +414,16 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
return NULL;
}
/*! get oldest connection in the list.
* \param[in] endp associated endpoint */
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
{
if (llist_empty(&endp->conns))
return NULL;
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" },

View File

@@ -56,147 +56,133 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
.sign_link = NULL,
};
/* The following EFR TRAU-DL frame is a dummy to be transmitted in the absence
* of RTP-derived TRAU-DL frames. The payload bit content here is the decoder
* homing frame (DHF) of TS 46.060 section 8.2 Table 7 - the best we can do
* in the absence of a proper TFO transform for EFR - while the full TRAU-DL
* frame was generated by passing said EFR DHF through osmo_rtp2trau().
*/
static const ubit_t idle_tf_efr[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 1, 0, 1, 1, 1,
1, 1, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 0, 1, 0,
1, 0, 0, 0, 1, 1, 1, 1,
1, 0, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 1, 0, 1,
0, 1, 1, 0, 0, 0, 0, 0,
1, 0, 0, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 0, 1,
1, 0, 0, 0, 0, 1, 1, 0,
0, 0, 0, 1, 1, 0, 0, 0,
1, 0, 0, 0, 1, 1, 1, 1,
0, 1, 1, 0, 1, 1, 0, 0,
1, 0, 0, 1, 1, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 1,
1, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 0,
1, 1, 1, 0, 1, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
/* EFR idle frame */
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
};
/* The following FRv1 TRAU-DL frame is a dummy to be transmitted in the absence
* of RTP-derived TRAU-DL frames. The payload bit content here is the silence
* frame of TS 46.011 Table 1 - the best we can do without integrating the
* TFO transform for FRv1 from Themyscira libgsmfr2 - while the full TRAU-DL
* frame was generated by passing said FRv1 silence frame through
* osmo_rtp2trau().
*/
static const ubit_t idle_tf_fr[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 0, 1, 0, 1, 0, 1, 1,
1, 1, 0, 0, 1, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 0, 1, 0, 0, 1, 0,
1, 1, 1, 0, 0, 1, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 1, 1,
1, 1, 0, 0, 0, 1, 0, 0,
1, 1, 1, 0, 1, 1, 0, 1,
1, 1, 0, 1, 1, 0, 0, 0,
1, 0, 0, 1, 1, 1, 0, 1,
1, 1, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 1, 1, 0,
0, 0, 1, 1, 1, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 0,
1, 1, 0, 1, 1, 0, 1, 1,
1, 0, 0, 0, 1, 0, 0, 1,
1, 1, 0, 1, 1, 0, 0, 0,
1, 0, 1, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 0, 0, 1, 1,
1, 0, 0, 0, 1, 0, 0, 1,
1, 1, 1, 0, 1, 1, 0, 1,
1, 0, 1, 1, 0, 0, 0, 1,
1, 0, 0, 1, 1, 1, 0, 1,
1, 0, 0, 0, 0, 1, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0,
1, 0, 1, 1, 1, 0, 0, 0,
1, 0, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 0, 1, 1,
0, 0, 0, 1, 0, 0, 1, 1,
1, 1, 0, 1, 1, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
/* FR idle frame */
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
};
/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
static const ubit_t idle_tf_spch[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
};
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
@@ -338,7 +324,7 @@ static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
#endif
/* Hand data over to the E1 stack */
e1inp_ts_send_raw(ts, msg);
msgb_enqueue(&ts->raw.tx_queue, msg);
return;
}
@@ -479,21 +465,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
{
if (strcmp(sdp_subtype_name, "GSM") == 0)
return OSMO_TRAU16_FT_FR;
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU16_FT_EFR;
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
if (i460_rate == OSMO_I460_RATE_16k)
return OSMO_TRAU16_FT_HR;
if (i460_rate == OSMO_I460_RATE_8k)
return OSMO_TRAU8_SPEECH;
LOGPENDP(endp, DE1, LOGL_ERROR,
"E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
return OSMO_TRAU_FT_NONE;
}
if (strcmp(sdp_subtype_name, "AMR") == 0) {
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
return OSMO_TRAU16_FT_HR;
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -511,11 +487,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
}
}
return OSMO_TRAU16_FT_AMR;
} else {
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_FT_NONE;
}
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_FT_NONE;
}
/* Determine a suitable TRAU frame type for a given codec */
@@ -524,21 +500,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
{
if (strcmp(sdp_subtype_name, "GSM") == 0)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
if (i460_rate == OSMO_I460_RATE_16k)
return OSMO_TRAU_SYNCP_16_FR_EFR;
if (i460_rate == OSMO_I460_RATE_8k)
return OSMO_TRAU_SYNCP_8_HR;
LOGPENDP(endp, DE1, LOGL_ERROR,
"E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
if (strcmp(sdp_subtype_name, "AMR") == 0) {
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
return OSMO_TRAU_SYNCP_8_HR;
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -556,11 +522,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
}
}
return OSMO_TRAU_SYNCP_16_FR_EFR;
} else {
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
sdp_subtype_name);
return OSMO_TRAU_SYNCP_16_FR_EFR;
}
/* Find out if a given TRAU frame type is AMR */
@@ -664,17 +630,15 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
struct mgcp_conn_rtp *conn_rtp;
struct mgcp_rtp_codec *codec;
enum osmo_tray_sync_pat_id sync_pat_id;
/* In order to determine the codec, find the oldest connection on
* the endpoint and use its codec information. Normally on an E1
* endpoint no more than one connection should exist. */
conn = mgcp_endp_get_conn_oldest(endp);
conn = mgcp_conn_get_oldest(endp);
OSMO_ASSERT(conn);
conn_rtp = mgcp_conn_get_conn_rtp(conn);
codec = conn_rtp->end.cset.codec;
codec = conn->u.rtp.end.codec;
OSMO_ASSERT(codec);
/* Update codec information */

View File

@@ -58,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
}
/* Generate E1 endpoint name from given numeric parameters */
static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr,
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
uint8_t ts_nr, uint8_t ss_nr)
{
unsigned int rate;
@@ -446,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname)
/* Check if the selected E1 endpoint is avalable, which means that none of
* the overlapping endpoints are currently serving a call. (if the system
* is properly configured such a situation should never ocurr!) */
static bool endp_avail_e1(const struct mgcp_endpoint *endp)
static bool endp_avail_e1(struct mgcp_endpoint *endp)
{
/* The following map shows the overlapping of the subslots and their
* respective rates. The numbers on the right running from top to bottom
@@ -552,7 +552,7 @@ static bool endp_avail_e1(const struct mgcp_endpoint *endp)
/*! check if an endpoint is available for any kind of operation.
* \param[in] endp endpoint to check.
* \returns true if endpoint is avalable, false it is blocked for any reason. */
bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
{
switch (endp->trunk->trunk_type) {
case MGCP_TRUNK_VIRTUAL:
@@ -569,24 +569,6 @@ bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
return false;
}
/*! Get number of conns in an endpoint.
* \param[in] endp endpoint to check.
* \returns Number of connections present in the endpoint. */
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp)
{
return llist_count(&endp->conns);
}
/*! check if an endpoint can in current state allocate new conns.
* \param[in] endp endpoint to check.
* \returns true if more connections can be allowed on endpoint, false if it is already busy. */
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp)
{
if (endp->type->max_conns == 0)
return false;
return mgcp_endp_num_conns(endp) >= endp->type->max_conns;
}
/*! claim endpoint, sets callid and activates endpoint, should be called at the
* beginning of the CRCX procedure when it is clear that a new call should be
* created.
@@ -673,97 +655,6 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
mgcp_endp_release(endp);
}
/*! free oldest connection in the list.
* \param[in] endp associated endpoint */
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
if (llist_empty(&endp->conns))
return;
conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
mgcp_conn_free(conn);
}
/*! free all connections at once.
* \param[in] endp associated endpoint */
#if defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
#endif
#endif
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
/* Drop all items in the list, might be consecutive! */
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
mgcp_conn_free(conn);
}
/*! find a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id)
{
struct mgcp_conn *conn;
const char *id_upper;
const char *conn_id;
if (!id || !*id)
return NULL;
/* Ignore leading zeros in needle */
while (*id == '0')
id++;
/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
* Connections" defines the id as a hex string, so clients may return lower case hex even though
* we sent upper case hex in the CRCX response. */
id_upper = osmo_str_toupper(id);
llist_for_each_entry(conn, &endp->conns, entry) {
/* Ignore leading zeros in haystack */
for (conn_id = conn->id; *conn_id == '0'; conn_id++);
if (strcmp(conn_id, id_upper) == 0)
return conn;
}
return NULL;
}
/*! get oldest connection in the list.
* \param[in] endp associated endpoint */
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp)
{
if (llist_empty(&endp->conns))
return NULL;
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
}
/*! find an RTP connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
const char *id)
{
struct mgcp_conn *conn;
conn = mgcp_endp_get_conn(endp, id);
if (!conn)
return NULL;
if (conn->type == MGCP_CONN_TYPE_RTP)
return mgcp_conn_get_conn_rtp(conn);
return NULL;
}
/*! release endpoint, all open connections are closed.
* \param[in] endp endpoint to release */
void mgcp_endp_release(struct mgcp_endpoint *endp)
@@ -774,7 +665,7 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
* 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_endp_free_conn_all(endp);
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 */

View File

@@ -264,7 +264,6 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
uint8_t *amr_data;
struct rtp_hdr *rtp_hdr;
struct amr_hdr *amr_hdr;
struct mgcp_rtp_codec *dst_codec;
int rc;
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
@@ -276,8 +275,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
}
msgb_pull_to_l3(msg);
dst_codec = conn_rtp_dst->end.cset.codec;
if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
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 */
@@ -305,7 +303,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
.extension = 0,
.padding = 0,
.version = 0,
.payload_type = dst_codec->payload_type,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = frame_nr,
.timestamp = 0,
@@ -470,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 rc;
int len;
OSMO_ASSERT(conn_src);
OSMO_ASSERT(conn_dst);
@@ -504,10 +502,9 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
* ignored by the receiver, but still it's useful for debug purposes
* to set it. Moreover, it seems ip.access nano3g produces much worse
* audio output on the air side if timestamp is not set properly. */
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
hdr->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",
@@ -517,15 +514,16 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
len = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
if (rc < 0)
return rc;
if (len <= 0)
return len;
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
return len;
}
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
@@ -546,13 +544,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
msgb_pull_to_l2(msg);
rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
/* rtph is further filled in mgcp_send_iuup() below. */
/* TODO: fill rtph properly: */
*rtph = (struct rtp_hdr){
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 2,
.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = 0,
.timestamp = 0,
@@ -647,7 +645,6 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
struct rtp_hdr *rtph;
int rc = -1;
int iuup_length = 0;
struct mgcp_rtp_codec *src_codec;
int8_t rfci;
/* Tx RNL-DATA.req */
@@ -660,14 +657,13 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
/* TODO: CMR handling & multiple frames handling */
src_codec = conn_src_rtp->end.cset.codec;
if (strcmp(src_codec->subtype_name, "AMR") != 0) {
if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
"Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
src_codec->subtype_name);
conn_src_rtp->end.codec->subtype_name);
goto free_ret;
}
if (mgcp_codec_amr_is_octet_aligned(src_codec)) {
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
if (msgb_length(msg) < (sizeof(*amr_hdr))) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,

View File

@@ -23,7 +23,6 @@
*/
#include <limits.h>
#include <ctype.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/osmux.h>
@@ -34,10 +33,6 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
/* (same fmt as LOGPENDP()) */
#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \
LOGP(DLMGCP, LEVEL, "endpoint:%s " FMT, (PDATA) ? ((PDATA)->epname ? : "null-epname") : "null-pdata", ##ARGS)
/*! Display an mgcp message on the log output.
* \param[in] message mgcp message string
* \param[in] len message mgcp message string length
@@ -81,24 +76,61 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
/*! Parse connection mode.
* \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
* \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */
enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
* \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 */
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
struct mgcp_conn *conn)
{
int ret = 0;
if (!mode)
return MGCP_CONN_NONE;
if (!mode) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"missing connection mode\n");
return -1;
}
if (!conn)
return -1;
if (!endp)
return -1;
if (strcasecmp(mode, "recvonly") == 0)
return MGCP_CONN_RECV_ONLY;
if (strcasecmp(mode, "sendrecv") == 0)
return MGCP_CONN_RECV_SEND;
if (strcasecmp(mode, "sendonly") == 0)
return MGCP_CONN_SEND_ONLY;
if (strcasecmp(mode, "confecho") == 0)
return MGCP_CONN_CONFECHO;
if (strcasecmp(mode, "loopback") == 0)
return MGCP_CONN_LOOPBACK;
return MGCP_CONN_NONE;
conn->mode = MGCP_CONN_RECV_ONLY;
else if (strcasecmp(mode, "sendrecv") == 0)
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 {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"unknown connection mode: '%s'\n", mode);
ret = -1;
}
/* Special handling for RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
}
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
mode, conn->mode);
/* Special handling für RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
conn->u.rtp.end.output_enabled);
}
/* The VTY might change the connection mode at any time, so we have
* to hold a copy of the original connection mode */
conn->mode_orig = conn->mode;
return ret;
}
/*! Analyze and parse the the hader of an MGCP messeage string.
@@ -127,7 +159,8 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
break;
case 2:
if (strcasecmp("MGCP", elem)) {
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
LOGP(DLMGCP, LOGL_ERROR,
"MGCP header parsing error\n");
return -510;
}
break;
@@ -140,87 +173,13 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
}
if (i != 4) {
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n");
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
return -510;
}
return 0;
}
static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line)
{
char *saveptr = NULL;
if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
return false;
line += strlen(MGCP_X_OSMO_IGN_HEADER);
while (1) {
char *token = strtok_r(line, " ", &saveptr);
line = NULL;
if (!token)
break;
if (!strcasecmp(token, "C"))
pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
else
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
}
return true;
}
/*! Analyze and parse the the header of an MGCP message string.
* \param[inout] pdata caller provided memory to store the parsing results.
* \returns 0 when parsing was successful, negative (MGCP cause code) on error. */
int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
{
struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
char *line;
mgcp_parse_hdr_pars_init(hp);
for_each_line(line, pdata->save) {
if (!mgcp_check_param(line)) {
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
continue;
}
switch (toupper(line[0])) {
case 'L':
hp->local_options = (const char *)line + 3;
break;
case 'C':
hp->callid = (const char *)line + 3;
break;
case 'I':
hp->connid = (const char *)line + 3;
break;
case 'M':
hp->mode = mgcp_parse_conn_mode((const char *)line + 3);
break;
case 'X':
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
hp->remote_osmux_cid = mgcp_parse_osmux_cid(line);
break;
}
if (parse_x_osmo_ign(pdata, line))
break;
/* Ignore unknown X-headers */
break;
case '\0':
hp->have_sdp = true;
goto mgcp_header_done;
default:
LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line);
return -539;
}
}
mgcp_header_done:
return 0;
}
/*! Extract OSMUX CID from an MGCP parameter line (string).
* \param[in] line single parameter line from the MGCP message
* \returns OSMUX CID, -1 wildcard, -2 on error */
@@ -231,19 +190,19 @@ int mgcp_parse_osmux_cid(const char *line)
if (strcasecmp(line + 2, "Osmux: *") == 0) {
LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
return -1;
}
if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
line);
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
return -2;
}
if (osmux_cid > OSMUX_CID_MAX) {
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
osmux_cid, OSMUX_CID_MAX);
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
return -2;
}
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
@@ -251,13 +210,20 @@ int mgcp_parse_osmux_cid(const char *line)
}
/*! Check MGCP parameter line (string) for plausibility.
* \param[in] endp pointer to endpoint (only used for log output, may be NULL)
* \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
* \param[in] line single parameter line from the MGCP message
* \returns true when line seems plausible, false on error */
bool mgcp_check_param(const char *line)
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
{
const size_t line_len = strlen(line);
if (line[0] != '\0' && line_len < 2)
if (line[0] != '\0' && line_len < 2) {
if (endp)
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
else
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
return false;
}
/* FIXME: A couple more checks wouldn't hurt... */
@@ -328,7 +294,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
}
/* Check if connection exists */
if (mgcp_endp_get_conn(endp, conn_id))
if (mgcp_conn_get(endp, conn_id))
return 0;
LOGPENDP(endp, DLMGCP, LOGL_ERROR,

View File

@@ -4,7 +4,6 @@
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -85,6 +84,12 @@ static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const ch
static int rx_rtp(struct msgb *msg);
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
{
return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
(osmo_sockaddr_is_any(&rtp_end->addr) == 0);
}
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address.
* \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
@@ -332,7 +337,7 @@ static int adjust_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
osmo_sockaddr_port(&addr->u.sa));
} else {
tsdelta = rtp_end->cset.codec->rate * 20 / 1000;
tsdelta = rtp_end->codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"Fixed packet duration and last timestamp delta "
"are not available, "
@@ -496,11 +501,11 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
}
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
if (!conn_dst->end.cset.codec) {
if (!conn_dst->end.codec) {
LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
return -EINVAL;
}
rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type;
rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
return 0;
}
@@ -523,8 +528,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
uint32_t timestamp, ssrc;
bool marker_bit;
struct rtp_hdr *rtp_hdr;
struct mgcp_rtp_codec *codec = rtp_end->cset.codec;
int payload = codec->payload_type;
int payload = rtp_end->codec->payload_type;
unsigned int len = msgb_length(msg);
if (len < sizeof(*rtp_hdr))
@@ -533,7 +537,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
seq = ntohs(rtp_hdr->sequence);
timestamp = ntohl(rtp_hdr->timestamp);
arrival_time = mgcp_get_current_ts(codec->rate);
arrival_time = mgcp_get_current_ts(rtp_end->codec->rate);
ssrc = ntohl(rtp_hdr->ssrc);
marker_bit = !!rtp_hdr->marker;
transit = arrival_time - timestamp;
@@ -542,16 +546,16 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
if (!state->initialized) {
state->initialized = 1;
state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end);
state->in_stream.last_seq = seq - 1;
state->in_stream.ssrc = ssrc;
state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
state->in_stream.last_tsdelta = 0;
state->packet_duration =
mgcp_rtp_packet_duration(endp, rtp_end);
state->out_stream.last_seq = seq - 1;
state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
state->out_stream.last_tsdelta = 0;
state->out_stream.last_timestamp = timestamp;
state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
state->patch.orig_ssrc = ssrc;
state->patch.patch_ssrc = rtp_end->force_constant_ssrc;
LOGPENDP(endp, DRTP, LOGL_INFO,
"initializing stream, SSRC: %u timestamp: %u "
"pkt-duration: %d, from %s:%d\n",
@@ -561,7 +565,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
osmo_sockaddr_port(&addr->u.sa));
if (state->packet_duration == 0) {
state->packet_duration =
codec->rate * 20 / 1000;
rtp_end->codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"fixed packet duration is not available, "
"using fixed 20ms instead: %d from %s:%d\n",
@@ -578,7 +582,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
osmo_sockaddr_port(&addr->u.sa));
state->in_stream.ssrc = ssrc;
if (state->patch.patch_ssrc) {
if (rtp_end->force_constant_ssrc) {
int16_t delta_seq;
/* Always increment seqno by 1 */
@@ -594,7 +598,10 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
delta_seq, timestamp, marker_bit);
state->patch.patch_ssrc = true;
ssrc = state->patch.orig_ssrc;
if (rtp_end->force_constant_ssrc != -1)
rtp_end->force_constant_ssrc -= 1;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"SSRC patching enabled, SSRC: %u "
@@ -814,8 +821,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
return;
hdr->version = 2;
hdr->payload_type = rtp_end->cset.codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
hdr->payload_type = rtp_end->codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
hdr->ssrc = state->alt_rtp_tx_ssrc;
}
@@ -1034,16 +1041,14 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
return -1;
}
/*! send message buffer via udp socket. If it succeeds, it takes ownership of the msgb and internally calls
* msgb_free() after the aynchronous sendto() completes. In case of error, the msgb is still owned by the
* caller and must be free'd accordingly.
/*! send message buffer via udp socket.
* \param[in] iofd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] msg message buffer that holds the data to be send.
* \returns 0 in case of success (takes msgb ownership), -1 on error (doesn't take msgb ownership). */
* \returns bytes sent, -1 on error. */
static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, struct msgb *msg)
{
LOGP(DRTP, LOGL_DEBUG, "sending %d bytes length packet to %s ...\n", msgb_length(msg),
LOGP(DRTP, LOGL_DEBUG, "sending %i bytes length packet to %s ...\n", msgb_length(msg),
osmo_sockaddr_to_str(addr));
return osmo_iofd_sendto_msgb(iofd, msg, 0, addr);
@@ -1054,7 +1059,7 @@ static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr
* \param[in] addr destination ip-address.
* \param[in] buf buffer that holds the data to be send.
* \param[in] len length of the data to be sent.
* \returns 0 in case of success, -1 on error. */
* \returns bytes sent, -1 on error. */
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len)
{
struct msgb *msg = msgb_alloc_c(iofd, len, "mgcp_udp_send");
@@ -1069,7 +1074,7 @@ int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, con
/*! send RTP dummy packet (to keep NAT connection open).
* \param[in] endp mcgp endpoint that holds the RTP connection.
* \param[in] conn associated RTP connection.
* \returns 0 in case of success, -1 on error. */
* \returns bytes sent, -1 on error. */
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int rc;
@@ -1105,7 +1110,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
rc = mgcp_udp_send(conn->end.rtcp, &rtcp_addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == 0)
if (rc >= 0)
return rc;
failed:
@@ -1181,8 +1186,6 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
struct mgcp_rtp_codec *src_codec;
struct mgcp_rtp_codec *dst_codec;
/* Make sure we have a valid RTP header, in cases where no RTP
* header is present, we will generate one. */
gen_rtp_header(msg, rtp_end, rtp_state);
@@ -1198,21 +1201,19 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
src_codec = conn_src->end.cset.codec;
dst_codec = conn_dst->end.cset.codec;
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(dst_codec)) {
rc = amr_oa_bwe_convert(endp, msg, dst_codec->param.amr_octet_aligned);
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
msgb_free(msg);
return rc;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(src_codec->subtype_name, "GSM-HR-08") == 0) {
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
@@ -1247,7 +1248,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
return 0;
} else if (!trunk->omit_rtcp) {
struct osmo_sockaddr rtcp_addr = rtp_end->addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(rtp_end->rtcp_port));
osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"send to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
@@ -1339,13 +1340,13 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
memcpy(&conn_src->end.addr, from_addr,
sizeof(conn_src->end.addr));
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
osmo_sockaddr_port(&conn_src->end.addr.u.sa));
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
@@ -1424,19 +1425,19 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
memcpy(&conn_src->end.addr, from_addr,
sizeof(conn_src->end.addr));
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
osmo_sockaddr_port(&conn_src->end.addr.u.sa));
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
/* Forward to E1 */
return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg);
return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
}
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1488,7 +1489,7 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
proto = (iofd == conn_src->end.rtp) ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
proto = (iofd == conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
if (res <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(-res));
@@ -1558,18 +1559,18 @@ static int rx_rtp(struct msgb *msg)
/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
if (mc->proto == MGCP_PROTO_RTP
&& conn_src->end.cset.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) {
&& conn_src->end.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
* communicated via SDP when the connection was created/modfied. */
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
goto out_free;
if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) {
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa);
msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
goto out_free;
}
}
@@ -1592,7 +1593,7 @@ static void rtp_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, co
int priv_nr = osmo_iofd_get_priv_nr(iofd);
char errbuf[129];
strerror_r(-res, errbuf, sizeof(errbuf));
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
LOG_CONN_RTP(conn_rtp, LOGL_NOTICE, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
osmo_sockaddr_to_str(daddr), errbuf);
}
}
@@ -1616,32 +1617,87 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr
NULL, 0, OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(dscp) |
OSMO_SOCK_F_PRIO(prio));
if (rc < 0) {
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%d).\n",
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
source_addr, port);
return -1;
}
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%d).\n", source_addr, port);
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
return rc;
}
/*! bind RTP port to endpoint/connection.
* \param[in] conn associated RTP connection.
* \param[in] rtp_port port number to bind on.
* \returns 0 on success, -1 on ERROR. */
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
char name[512];
struct mgcp_conn *conn = conn_rtp->conn;
struct mgcp_config *cfg = conn->endp->trunk->cfg;
struct mgcp_rtp_end *end = &conn_rtp->end;
int rc, rtp_fd, rtcp_fd;
snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id);
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
rc = mgcp_create_bind(source_addr, rtp_end->local_port, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTP port: %s:%d\n",
source_addr, rtp_end->local_port);
goto cleanup0;
}
rtp_fd = rc;
rc = mgcp_create_bind(source_addr, rtp_end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTCP port: %s:%d\n",
source_addr, rtp_end->local_port + 1);
goto cleanup1;
}
rtcp_fd = rc;
if (osmo_iofd_register(rtp_end->rtp, rtp_fd) < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTP port %d\n",
rtp_end->local_port);
goto cleanup2;
}
if (osmo_iofd_register(rtp_end->rtcp, rtcp_fd) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTCP port %d\n",
rtp_end->local_port + 1);
goto cleanup3;
}
return 0;
cleanup3:
osmo_iofd_unregister(rtp_end->rtp);
cleanup2:
close(rtcp_fd);
cleanup1:
close(rtp_fd);
cleanup0:
return -1;
}
/*! bind RTP port to endpoint/connection.
* \param[in] endp endpoint that holds the RTP connection.
* \param[in] rtp_port port number to bind on.
* \param[in] conn associated RTP connection.
* \returns 0 on success, -1 on ERROR. */
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn)
{
char name[512];
struct mgcp_rtp_end *end;
snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
(end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%u was already bound\n", rtp_port);
LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
rtp_port, mgcp_conn_dump(conn->conn));
/* Double bindings should never occour! Since we always allocate
* connections dynamically and free them when they are not
* needed anymore, there must be no previous binding leftover.
@@ -1651,55 +1707,33 @@ int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
}
end->local_port = rtp_port;
end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtp)
goto free_iofd_ret;
return -EIO;
osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
end->rtcp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
if (!end->rtcp)
goto free_iofd_ret;
end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtcp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
}
osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
rc = mgcp_create_bind(end->local_addr, end->local_port, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTP port: %s:%d\n", end->local_addr, end->local_port);
goto free_iofd_ret;
}
rtp_fd = rc;
rc = mgcp_create_bind(end->local_addr, end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTCP port: %s:%d\n", end->local_addr, end->local_port + 1);
goto cleanup1;
}
rtcp_fd = rc;
if (osmo_iofd_register(end->rtp, rtp_fd) < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTP port %d\n", end->local_port);
goto cleanup2;
}
if (osmo_iofd_register(end->rtcp, rtcp_fd) != 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTCP port %d\n", end->local_port + 1);
goto cleanup3;
}
return 0;
cleanup3:
osmo_iofd_unregister(end->rtp);
cleanup2:
close(rtcp_fd);
cleanup1:
close(rtp_fd);
free_iofd_ret:
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
}
/*! free allocated RTP and RTCP ports.
* \param[in] end RTP end */
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
}
if (end->rtcp) {
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
}
}

View File

@@ -1,7 +1,6 @@
/*
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
* (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All rights not specifically granted under this license are reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -265,7 +264,7 @@ osmux_conn_lookup(const struct mgcp_trunk *trunk, uint8_t local_cid, const struc
if (conn->type != MGCP_CONN_TYPE_RTP)
continue;
conn_rtp = mgcp_conn_get_conn_rtp(conn);
conn_rtp = &conn->u.rtp;
if (!mgcp_conn_rtp_is_osmux(conn_rtp))
continue;
@@ -651,7 +650,7 @@ int conn_osmux_enable(struct mgcp_conn_rtp *conn)
osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
(conn->osmux.remote_cid * rtp_ssrc_winlen) +
(random() % rtp_ssrc_winlen));
osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type);
osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.codec->payload_type);
osmux_xfrm_output_set_tx_cb(conn->osmux.out,
scheduled_from_osmux_tx_rtp_cb, conn);
@@ -695,7 +694,7 @@ void conn_osmux_disable(struct mgcp_conn_rtp *conn)
/*! send RTP dummy packet to OSMUX connection port.
* \param[in] conn associated RTP connection
* \returns 0 in case of success, -1 on error */
* \returns bytes sent, -1 on error */
int osmux_send_dummy(struct mgcp_conn_rtp *conn)
{
char ipbuf[INET6_ADDRSTRLEN];

File diff suppressed because it is too large Load Diff

View File

@@ -1,104 +0,0 @@
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/mgcp/mgcp_rtp_end.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
/***********************
* mgcp_rtp_end
**********************/
void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp)
{
struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk;
struct mgcp_config *cfg = trunk->cfg;
end->conn_rtp = conn_rtp;
end->rtp = NULL;
end->rtcp = NULL;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;
/* Set default values */
end->frames_per_packet = 0; /* unknown */
end->output_enabled = false;
end->maximum_packet_time = -1;
end->force_aligned_timing = trunk->force_aligned_timing;
end->force_constant_ssrc = trunk->force_constant_ssrc;
end->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
if (cfg->force_ptime) {
end->packet_duration_ms = cfg->force_ptime;
end->force_output_ptime = 1;
} else {
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
}
/* Make sure codec table is reset */
mgcp_codecset_reset(&end->cset);
}
void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end)
{
mgcp_rtp_end_free_port(end);
mgcp_codecset_reset(&end->cset);
}
void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms)
{
if (end->force_output_ptime)
return;
end->packet_duration_ms = packet_duration_ms;
}
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
{
return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
(osmo_sockaddr_is_any(&rtp_end->addr) == 0);
}
/*! free allocated RTP and RTCP ports.
* \param[in] end RTP end */
void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end)
{
if (end->rtp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
}
if (end->rtcp) {
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
}
}

View File

@@ -312,13 +312,16 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
}
/*! Analyze SDP input string.
* \param[inout] p provided memory to store the parsing results.
* \param[in] endp trunk endpoint.
* \param[out] conn associated rtp connection.
* \param[out] caller provided memory to store the parsing results.
*
* Note: In conn (conn->end) the function returns the packet duration,
* rtp port, rtcp port and the codec information.
* \returns 0 on success, -1 on failure. */
int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
{
OSMO_ASSERT(p);
struct mgcp_parse_sdp *sdp = &p->sdp;
struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
unsigned int codecs_used = 0;
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
@@ -328,14 +331,19 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
char *line;
unsigned int i;
void *tmp_ctx = talloc_new(NULL);
struct mgcp_rtp_end *rtp;
int payload_type;
int ptime, ptime2 = 0;
char audio_name[64];
int port, rc;
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
OSMO_ASSERT(p);
rtp = &conn->end;
memset(&codecs, 0, sizeof(codecs));
mgcp_parse_sdp_init(sdp);
for_each_line(line, p->save) {
switch (line[0]) {
@@ -353,19 +361,19 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
if (ptime2 > 0 && ptime2 != ptime)
sdp->ptime = 0;
rtp->packet_duration_ms = 0;
else
sdp->ptime = ptime;
rtp->packet_duration_ms = ptime;
break;
}
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
sdp->maxptime = ptime2;
rtp->maximum_packet_time = ptime2;
break;
}
if (strncmp("a=fmtp:", line, 6) == 0) {
rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
if (rc >= 0)
fmtp_used++;
break;
@@ -374,23 +382,33 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
break;
case 'm':
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
if (rc == 1)
sdp->rtp_port = port;
if (rc == 1) {
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
rtp->rtcp_port = htons(port + 1);
}
rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
rc = pt_from_sdp(conn->conn, codecs,
ARRAY_SIZE(codecs), line);
if (rc > 0)
codecs_used = rc;
break;
case 'c':
if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
talloc_free(tmp_ctx);
return -1;
}
break;
default:
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d on %s\n",
line[0], line[0], p->epname);
if (endp)
/* TODO: Check spec: We used the bare endpoint number before,
* now we use the endpoint name as a whole? Is this allowed? */
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d on %s\n",
line[0], line[0], endp->name);
else
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d\n",
line[0], line[0]);
break;
}
}
@@ -404,22 +422,23 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
/* Store parsed codec information */
for (i = 0; i < codecs_used; i++) {
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
if (rc < 0)
LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
}
talloc_free(tmp_ctx);
LOGP(DLMGCP, LOGL_NOTICE,
"%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
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");
for (i = 0; i < codecs_used; i++) {
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
sdp->cset.codecs[i].payload_type,
strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
rtp->codecs[i].payload_type,
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
LOGPC(DLMGCP, LOGL_NOTICE, " ");
}
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
@@ -523,7 +542,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
OSMO_ASSERT(sdp);
OSMO_ASSERT(addr);
codec = conn->end.cset.codec;
codec = conn->end.codec;
audio_name = codec->audio_name;
payload_type = codec->payload_type;

View File

@@ -141,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
* keep this option open: */
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn));
mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
break;
default:
break;

View File

@@ -306,43 +306,3 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne
return NULL;
}
/* Try to find a free port by attempting to bind on it. Also handle the
* counter that points on the next free port. Since we have a pointer
* to the next free port, binding should in work on the first attempt in
* general. In case of failure the next port is tried until the whole port
* range is tried once. */
int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
{
int i;
struct mgcp_port_range *range;
unsigned int tries;
OSMO_ASSERT(trunk);
OSMO_ASSERT(conn_rtp);
range = &trunk->cfg->net_ports;
pthread_mutex_lock(&range->lock);
/* attempt to find a port */
tries = (range->range_end - range->range_start) / 2;
for (i = 0; i < tries; ++i) {
int rc;
if (range->last_port >= range->range_end)
range->last_port = range->range_start;
rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port);
range->last_port += 2;
if (rc == 0) {
pthread_mutex_unlock(&range->lock);
return 0;
}
}
pthread_mutex_unlock(&range->lock);
LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR,
"Allocating a RTP/RTCP port failed %u times.\n", tries);
return -1;
}

View File

@@ -165,7 +165,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_state *state = &conn->state;
struct mgcp_rtp_end *end = &conn->end;
struct mgcp_rtp_codec *codec = end->cset.codec;
struct mgcp_rtp_codec *codec = end->codec;
struct rate_ctr *tx_packets, *tx_bytes;
struct rate_ctr *rx_packets, *rx_bytes;
struct rate_ctr *dropped_packets;
@@ -254,8 +254,7 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
* connection types (E1) as soon as
* the implementation is available */
if (conn->type == MGCP_CONN_TYPE_RTP) {
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
dump_rtp_end(vty, conn_rtp);
dump_rtp_end(vty, &conn->u.rtp);
}
}
}
@@ -857,7 +856,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc,
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
trunk->force_constant_ssrc = true;
trunk->force_constant_ssrc = 1;
return CMD_SUCCESS;
}
@@ -868,7 +867,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc,
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
trunk->force_constant_ssrc = false;
trunk->force_constant_ssrc = 0;
return CMD_SUCCESS;
}
@@ -923,7 +922,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp,
{
struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
OSMO_ASSERT(trunk);
trunk->force_constant_ssrc = false;
trunk->force_constant_ssrc = 0;
trunk->force_aligned_timing = 0;
trunk->rfc5993_hr_convert = false;
return CMD_SUCCESS;
@@ -1197,7 +1196,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc,
"rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
{
struct mgcp_trunk *trunk = vty->index;
trunk->force_constant_ssrc = true;
trunk->force_constant_ssrc = 1;
return CMD_SUCCESS;
}
@@ -1207,7 +1206,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc,
"no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
{
struct mgcp_trunk *trunk = vty->index;
trunk->force_constant_ssrc = false;
trunk->force_constant_ssrc = 0;
return CMD_SUCCESS;
}
@@ -1257,7 +1256,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp,
"no rtp-patch", NO_STR RTP_PATCH_STR)
{
struct mgcp_trunk *trunk = vty->index;
trunk->force_constant_ssrc = false;
trunk->force_constant_ssrc = 0;
trunk->force_aligned_timing = 0;
trunk->rfc5993_hr_convert = false;
return CMD_SUCCESS;
@@ -1358,11 +1357,10 @@ DEFUN(loop_conn,
endp = trunk->endpoints[endp_no];
int loop = atoi(argv[2]);
llist_for_each_entry(conn, &endp->conns, entry) {
if (conn->type == MGCP_CONN_TYPE_RTP) {
if (conn->type == MGCP_CONN_TYPE_RTP)
/* Handle it like a MDCX, switch on SSRC patching if enabled */
struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
conn_rtp->state.patch.patch_ssrc = true;
} else {
mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end);
else {
/* FIXME: Introduce support for other connection (E1)
* types when implementation is available */
vty_out(vty, "%%Can't enable SSRC patching,"
@@ -1420,7 +1418,7 @@ DEFUN(tap_rtp,
endp = trunk->endpoints[endp_no];
conn_id = argv[2];
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
if (!conn) {
vty_out(vty, "Conn ID %s is invalid.%s",
conn_id, VTY_NEWLINE);

View File

@@ -103,7 +103,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
@@ -115,7 +115,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
@@ -127,49 +127,40 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_ADDR0000 \
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_ADDR0000_RET \
"200 18983216 OK\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"527 18983216 FAIL\r\n"
#define MDCX4 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -181,7 +172,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -193,87 +184,87 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 112\r\n" \
"a=rtpmap:112 AMR\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT1 \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: SENDRECV\r\n" \
"M: SENDRECV\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT2 \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT3 \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
/* Test different upper/lower case in options */
#define MDCX4_PT4 \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"m: sendrecv\r\n" \
"m: sendrecv\r" \
"c: 2\r\n" \
"i: %s\r\n" \
"l: A:amr, NT:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_SO \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
@@ -306,7 +297,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET \
"200 2 OK\r\n" \
@@ -319,7 +310,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
@@ -331,7 +322,7 @@ static void test_strline(void)
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
@@ -344,17 +335,17 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_ZYN \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"C: 2\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n"
"\n" \
"v=0\r" \
"c=IN IP4 123.12.12.123\r" \
"m=audio 5904 RTP/AVP 97\r" \
"a=rtpmap:97 GSM-EFR/8000\r"
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
@@ -380,7 +371,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_X_OSMO_IGN_RET \
"200 2 OK\r\n" \
@@ -393,95 +384,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16010 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0 \
"CRCX 3 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_RET \
"200 3 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16014 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP_RET \
"200 4 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16016 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX in m=sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX using sendrecv mode in the SDP part */
#define CRCX_PORT_0_IUFP_SENDRECV2 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"a=sendrecv\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX entirely omitting a mode, i.e. implcit sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV3 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
@@ -538,7 +441,7 @@ static void test_strline(void)
"m=audio 5904 RTP/AVP 18 97\r\n" \
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
@@ -553,7 +456,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
@@ -568,7 +471,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
@@ -583,7 +486,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
@@ -672,7 +575,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_NULL_RET "502 2 FAIL\r\n"
@@ -720,11 +623,6 @@ static const struct mgcp_test tests[] = {
{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
{"CRCX_PORT_0", CRCX_PORT_0, CRCX_PORT_0_RET, 97},
{"CRCX_PORT_0_IUFP", CRCX_PORT_0_IUFP, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV", CRCX_PORT_0_IUFP_SENDRECV, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV2", CRCX_PORT_0_IUFP_SENDRECV2, CRCX_PORT_0_IUFP_RET, 96},
{"CRCX_PORT_0_IUFP_SENDRECV3", CRCX_PORT_0_IUFP_SENDRECV3, CRCX_PORT_0_IUFP_RET, 96},
};
static const struct mgcp_test retransmit[] = {
@@ -755,13 +653,12 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
static int dummy_packets = 0;
/* override and forward */
int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
uint32_t dest_host =
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
const uint8_t *buf = msgb_data(msg);
size_t len = msgb_length(msg);
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
if (len == sizeof(rtp_dummy_payload)
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
@@ -775,8 +672,6 @@ int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags,
OSMO_ASSERT(dest_host);
OSMO_ASSERT(dest_port);
msgb_free(msg);
return len;
}
@@ -965,7 +860,7 @@ static void test_messages(void)
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, "1");
conn = mgcp_conn_get_rtp(endp, "1");
if (conn) {
OSMO_ASSERT(conn);
@@ -1023,14 +918,14 @@ static void test_messages(void)
fprintf(stderr, "endpoint:%s: "
"payload type %d (expected %d)\n",
last_endpoint,
conn->end.cset.codec->payload_type, t->ptype);
conn->end.codec->payload_type, t->ptype);
if (t->ptype != PTYPE_IGNORE)
OSMO_ASSERT(conn->end.cset.codec->payload_type ==
OSMO_ASSERT(conn->end.codec->payload_type ==
t->ptype);
/* Reset them again for next test */
conn->end.cset.codec->payload_type = PTYPE_NONE;
conn->end.codec->payload_type = PTYPE_NONE;
}
}
@@ -1208,9 +1103,7 @@ static void test_packet_loss_calc(void)
_conn =
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
state = &conn->state;
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
@@ -1230,7 +1123,7 @@ static void test_packet_loss_calc(void)
pl_test_dat[i].expected);
}
mgcp_endp_free_conn_all(&endp);
mgcp_conn_free_all(&endp);
}
talloc_free(trunk);
@@ -1461,13 +1354,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
rtp = &conn->end;
OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->cset.codec = &rtp->cset.codecs[0];
OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->codec = &rtp->codecs[0];
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
struct rtp_packet_info *info = test_rtp_packets1 + i;
@@ -1479,6 +1372,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
OSMO_ASSERT(info->len >= 0);
msg->l3h = msgb_put(msg, info->len);
memcpy((char*)msgb_l3(msg), info->data, info->len);
mgcp_rtp_end_config(&endp, 1, rtp);
mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
@@ -1512,7 +1406,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
}
force_monotonic_time_us = -1;
mgcp_endp_free_conn_all(&endp);
mgcp_conn_free_all(&endp);
talloc_free(trunk);
talloc_free(cfg);
}
@@ -1547,9 +1441,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 2@mgw with three codecs, last one ignored */
last_endpoint[0] = '\0';
@@ -1563,9 +1457,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 3@mgw with no codecs, check for PT == 0 */
/* Note: It usually makes no sense to leave the payload type list
@@ -1584,9 +1478,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
/* Allocate 4@mgw with a single codec */
last_endpoint[0] = '\0';
@@ -1600,9 +1494,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
last_endpoint[0] = '\0';
@@ -1616,9 +1510,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
inp = create_msg(MDCX_NAT_DUMMY, conn_id);
last_endpoint[0] = '\0';
@@ -1628,9 +1522,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 3);
OSMO_ASSERT(conn->end.codec->payload_type == 3);
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
memset(&addr, 0, sizeof(addr));
inet_aton("8.8.8.8", &addr);
@@ -1645,7 +1539,7 @@ static void test_multilple_codec(void)
talloc_free(endp->last_response);
talloc_free(endp->last_trans);
endp->last_response = endp->last_trans = NULL;
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(!conn);
last_endpoint[0] = '\0';
@@ -1659,9 +1553,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
mgcp_endpoints_release(trunk);
talloc_free(cfg);
@@ -1688,7 +1582,7 @@ static void test_no_cycle(void)
_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(endp, _conn->id);
conn = mgcp_conn_get_rtp(endp, _conn->id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->state.stats.initialized == 0);
@@ -2194,7 +2088,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
int payload_type_conn_dst;
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
if (expect->payload_type_map[index_conn_src] == -EINVAL
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
printf(" codec decision failed (expected)!\n");
@@ -2204,19 +2098,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
}
} else {
printf(" Codec decision result:\n");
if (conn[index_conn_src].end.cset.codec) {
payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
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.cset.codec->subtype_name, payload_type_conn_src);
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.cset.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
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.cset.codec->subtype_name,
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
payload_type_conn_dst);
} else {
payload_type_conn_dst = -EINVAL;
@@ -2264,8 +2158,8 @@ static void test_mgcp_codec_decide(void)
if (!codec->audio_name)
break;
rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, 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 ?
@@ -2331,7 +2225,7 @@ void test_conn_id_matching(void)
for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
const char *needle = conn_id_request[i];
printf("needle='%s' ", needle);
conn_match = mgcp_endp_get_conn(&endp, needle);
conn_match = mgcp_conn_get(&endp, needle);
OSMO_ASSERT(conn_match);
printf("found '%s'\n", conn_match->id);
OSMO_ASSERT(conn_match == conn);

View File

@@ -73,7 +73,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
a=ptime:40
---------8<---------
checking response:
@@ -101,42 +101,40 @@ Testing MDCX4_ADDR000
creating message from statically defined input:
---------8<---------
MDCX 18983216 1@mgw MGCP 1.0
M: sendrecv
C: 2
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 0.0.0.0
c=IN IP4 0.0.0.0
t=0 0
m=audio 4441 RTP/AVP 99
a=ptime:20
a=rtpmap:99 AMR/8000
a=ptime:40
---------8<---------
using message with patched conn_id for comparison
checking response:
using message as statically defined for comparison
(response contains a connection id)
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX4
creating message from statically defined input:
---------8<---------
M: sendrecv
C: 2
MDCX 18983217 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
a=ptime:20
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -150,18 +148,17 @@ Testing MDCX4_PT1
================================================
Testing MDCX4_PT1
creating message from statically defined input:
M: SENDRECV
C: 2
---------8<---------
MDCX 18983218 1@mgw MGCP 1.0
M: SENDRECV
C: 2
I: %s
L: p:20-40, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
a=ptime:20
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -175,18 +172,17 @@ Testing MDCX4_PT2
================================================
Testing MDCX4_PT2
M: sendrecv
C: 2
creating message from statically defined input:
---------8<---------
MDCX 18983219 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20-20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
a=ptime:20
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
@@ -200,18 +196,17 @@ Testing MDCX4_PT3
Dummy packets: 2
================================================
M: sendrecv
C: 2
Testing MDCX4_PT3
creating message from statically defined input:
---------8<---------
MDCX 18983220 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: a:AMR, nt:IN
v=0
a=ptime:20
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
@@ -225,18 +220,17 @@ Testing MDCX4_PT4
(response contains a connection id)
Dummy packets: 2
m: sendrecv
c: 2
================================================
Testing MDCX4_PT4
creating message from statically defined input:
---------8<---------
MDCX 18983221 1@mgw MGCP 1.0
m: sendrecv
c: 2
i: %s
l: A:amr, NT:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
@@ -250,18 +244,17 @@ Testing MDCX4_SO
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
M: sendonly
C: 2
================================================
Testing MDCX4_SO
creating message from statically defined input:
---------8<---------
MDCX 18983222 1@mgw MGCP 1.0
M: sendonly
C: 2
I: %s
L: p:20, a:AMR, nt:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
@@ -274,8 +267,7 @@ Testing MDCX4_RO
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
M: recvonly
C: 2
(response contains a connection id)
================================================
Testing MDCX4_RO
@@ -304,15 +296,9 @@ Response matches our expectations.
---------8<---------
checking response:
CRCX 2 1@mgw MGCP 1.0
M: recvonly
C: 2
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX_ZYN
@@ -428,7 +414,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing CRCX
creating message from statically defined input:
---------8<---------
@@ -493,7 +479,7 @@ v=0
(response contains a connection id)
================================================
a=ptime:20
Testing CRCX
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
@@ -564,7 +550,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing CRCX_NULL
creating message from statically defined input:
---------8<---------
@@ -613,110 +599,6 @@ using message as statically defined for comparison
(response does not contain a connection id)
================================================
================================================
Testing CRCX_PORT_0
creating message from statically defined input:
---------8<---------
CRCX 3 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
M: sendrecv
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV2
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
a=sendrecv
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV3
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
Testing RQNT_NULL
creating message from statically defined input:
---------8<---------
@@ -730,7 +612,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing CRCX
creating message from statically defined input:
---------8<---------
@@ -748,7 +630,7 @@ v=0
---------8<---------
checking response:
using message with patched conn_id for comparison
a=ptime:20
Response matches our expectations.
Re-transmitting CRCX
creating message from statically defined input:
---------8<---------
@@ -860,7 +742,7 @@ v=0
---------8<---------
checking response:
using message as statically defined for comparison
a=ptime:20
Response matches our expectations.
Testing packet loss calculation.
creating message from statically defined input:
---------8<---------
@@ -1314,7 +1196,7 @@ c=IN IP4 123.12.12.123
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 5, Transit = -163760
Testing multiple payload types
a=ptime:20
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
M: recvonly
@@ -1331,7 +1213,7 @@ m=audio 5904 RTP/AVP 18 97 101
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 2@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1348,7 +1230,7 @@ m=audio 5904 RTP/AVP
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 3@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1365,7 +1247,7 @@ m=audio 5904 RTP/AVP 18
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 4@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1447,7 +1329,7 @@ v=0
a=recvonly
---------8<---------
a=ptime:20
Testing no sequence flow on initial packet
Testing no rtpmap name
creating message from statically defined input:
---------8<---------