Compare commits

...

25 Commits

Author SHA1 Message Date
Oliver Smith
9c3fad2c42 Bump version: 1.13.0.3-227a → 1.13.1
Change-Id: I8ebbaf6bff440cb233088f4bc226b80db0fd3922
2024-09-12 13:54:42 +02:00
Pau Espin Pedrol
227a800d26 tests/mgcp/mgcp_test: Add some extra asserts in code
This makes it easier to catch possible failures while running the test,
plus makes gcc on OpenSUSE_Factory happy and not warn.

Related: OS#5044
Change-Id: I01c3c84e58a11055f0e0a6955016dc2489c73379
2024-08-20 12:02:02 +02:00
Philipp Maier
24cae67f3e mgcp_network: add missing ntohs
We must use ntohs before passing the RTCP port to osmo_sockaddr_port

Related: OS#6527
Change-Id: I9773c7b1fda8c9b429723ef9f0db0b58894b28fe
2024-08-07 09:48:45 +02:00
Philipp Maier
0d47c408ac mgcp_network: use an uint16_t to store the port number
The comment in struct mgcp_rtp_end says that the RTCP port number has to
be stored in network byte order. Such a port number is 16 bit long, so
let's use an uint16_t instead of an int here.

Related: OS#6527
Change-Id: I392b07b243389a78d4ad1d784cdfdc28ec59b487
2024-08-07 09:47:42 +02:00
Oliver Smith
f1b557988d Bump version: 1.12.1.58-95e50-dirty → 1.13.0
Change-Id: I46cabfda147bf700fb29a0b8eecf54560a1d378d
2024-07-24 16:23:15 +02:00
Mychaela N. Falconia
95e504aa97 fix E1 TS output when used with osmo-e1d
The original code did E1 raw TS output by posting directly to
&ts->raw.tx_queue instead of calling e1inp_ts_send_raw();
doing so bypasses the call to driver->want_write performed in
e1inp layer.  This approach worked for DAHDI where no
select-for-write is used; however, e1inp interface to osmo-e1d
does use select-for-write, hence applications like osmo-mgw
do need to use e1inp_ts_send_raw() API in order to work
correctly.

Change-Id: I6ce9a1dea6834632faf75059e85ca9a0c25d57c2
2024-07-23 14:24:18 +00:00
Neels Hofmeyr
a5ae091fdd do not FAIL on CRCX in sendrecv mode
Currently, a CRCX in sendrecv mode results in:

  DLMGCP ERROR endpoint:rtpbridge/2@mgw CI:7F4C8EDD CRCX: selected connection mode type requires an opposite end! (mgcp_protocol.c:1090)

But it is not actually practical, nor logical to require another conn
for the 'sendrecv' ConnectionMode.

Impractical: If I want to create two conns on an endpoint that both are
in 'sendrecv' mode, I have to send two CRCX, one for each conn. At the
time of the first CRCX, there cannot be any other conn, so I am
currently forced to send a different ConnectionMode in the CRCX,
followed by another MDCX later, just to change the first conn to
sendrecv.

Illogical: In a situation where two conns are currently in sendrecv
mode, if I now DLCX one of them, I can legally reach a state with a
single conn in sendrecv mode, just as currently forbidden for CRCX.

In general, MGCP is not forcing any particular number of connections.

Simply start forwarding RTP as soon as there is a remote conn, and not
require another explicit MDCX.

Related: SYS#6974 SYS#6907
Related: osmo-ttcn3-hacks I00fd854f058f7f53e2f579e8481ca2b9253f08e3
Change-Id: Ic089485543c5c97a35c7ae24fe0f622bf57d1976
2024-07-02 01:54:45 +00:00
Neels Hofmeyr
249f799a88 mgcp_test: add CRCX for IUFP in sendrecv
Note, there are also ttcn3 tests sending the same to osmo-mgw being
submitted along with these patches, and the ttcn3 tests currently fail:
osmo-mgw rejects the connection mode "sendrecv" in the first CRCX.

Change-Id: Icdb1085b8e44ac4cff6c457163349b81e81bf765
2024-07-02 01:54:45 +00:00
Neels Hofmeyr
dc395843ff mgcp_test: test a=ptime:20, not 40
In our GSM world, the packet time is 20 ms, hence 20 is the typical
value that we should test. Maybe we can do one test with 40 at most, but
we'll most probably never see anything else than 20 in practice.

Change-Id: Ia2292198bf6e3b72912afd69607654ca77fd549d
2024-07-02 01:54:45 +00:00
Neels Hofmeyr
c5d003e09e mgcp_test.c: fix various missing '\r' and '\n'
The only valid line endings are '\n' and '\r\n'.
We usually use '\r\n' like we were in MSDOS.

MGCP, RFC3435 3.1:

   Headers and session descriptions are encoded as a set of text lines,
   separated by a carriage return and line feed character (or,
   optionally, a single line-feed character).

SDP, RFC8866 5:

   The sequence CRLF (0x0d0a) is used to end a line,
   although parsers SHOULD be tolerant and also accept lines terminated
   with a single newline character.

There should probably be tests for '\n' line endings, but mixing them in
the same MGCP message is ridiculous.

Change-Id: I6d530535a3a5f1d1a0716ab9e4a8079ba1de242e
2024-07-02 01:54:45 +00:00
Mychaela N. Falconia
e6398d886b E1: support HRv1 codec on both 16k and 8k subslots
HRv1 support in OsmoMGW-E1 was previously broken (couldn't work
on either 16k or 8k subslots) because of inconsistency: the TRAU
frame type was set to OSMO_TRAU16_FT_HR, but the TRAU sync pattern
was set to OSMO_TRAU_SYNCP_8_HR.  However, now that libosmotrau
has proper support for HRv1 TRAU frame encoding and RTP conversion
in both 16k and 8k formats, drive it correctly in OsmoMGW-E1.

While at it, change the code structure to avoid else-after-return.
Was the original code written and merged in a time before strict
linter checks?

Change-Id: Ifadbdc68905178c6ffdd673a6fb71c18610c9847
2024-06-26 17:45:49 +00:00
Neels Hofmeyr
23140d6f94 mgcp_test.c: verify osmo-mgw accepts m=audio 0
When osmo-hnbgw does not yet know the remote port, it wants to send a
CRCX to set up IuUP at the MGW, with the audio port set to zero.
Make sure osmo-mgw accepts port == 0.

Related: SYS#6907 SYS#6974
Change-Id: I42011c2e7256d372a37b6a2fe86af0153038e2d0
2024-06-14 16:14:41 +02:00
Neels Hofmeyr
36c823eef1 mgcp-client: always send 'm=audio' line
Re-add the m=audio line to SDP emitted from libosmo-mgcp-client, even if
the audio port is not set yet

Patch a5acaa68db introduced a presence
flag for the RTP audio port number. This flag, when unset, also omitted
the 'm=audio...' line completely, dropping the PT number definitions.

Correct:

  m=audio 1234 RTP/AVP 96             <--- anounce 96
  a=rtpmap:96 VND.3GPP.IUFP/16000     <--- further specify 96
  a=fmtp:96 ...                       <--- further specify 96

When m=audio is missing, we only have orphaned rtpmap and fmtp entries.
They are supposed to further specify the 96 listed in 'RTP/AVP 96',
instead they are without context:

  a=rtpmap:96 VND.3GPP.IUFP/16000
  a=fmtp:96 ...

When the presence map indicates no port known, we still need to emit the
list of PT numbers; so we're forced to send a port of 0:

  m=audio 0 RTP/AVP 96
  a=rtpmap:96 VND.3GPP.IUFP/16000
  a=fmtp:96 ...

This is an important fix for osmo-hnbgw, which sends the first CRCX with
an IUFP codec, at a time when the remote port is not yet known. osmo-mgw
requires an m=audio line to accept incoming IuUP Initializaition
requests. When m=audio is missing, osmo-mgw does not parse the IUFP
codec, and 3G voice fails completely. This mgcp-client patch will emit
valid codec config also when port == 0, fixing osmo-hnbgw voice, because
osmo-mgw will know about IUFP from the start.

Related: SYS#6907 SYS#6974
Related: osmo-mgw a5acaa68db
Change-Id: Id95b629453aec999100b5af821c6a0b9562bb597
2024-06-14 16:14:25 +02:00
Oliver Smith
fa393fa1e9 doc: example configs: fix deprecation warnings
Fix for:
  range must end at an odd port number, autocorrecting port (16000) to: 16001
  % Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect
  % Deprecated 'sdp audio-payload name NAME' config no longer has any effect
  % Deprecated 'loop (0|1)' config no longer has any effect

Change-Id: I62a4fd119de48039c3c450d5323d8f9b7de8120f
2024-05-15 11:58:52 +00:00
Oliver Smith
e0fc37a437 contrib/systemd: run as osmocom user
I have verified that with AmbientCapabilities=CAP_SYS_NICE, setting
scheduling policy as described in the manual still works as expected.

Related: OS#4107
Change-Id: Ibb83c231231b39dc6732c0f375aeb3b21f3938ef
2024-05-14 15:25:21 +02:00
Oliver Smith
4aa2b0e35b contrib: remove rpm spec file
Related: https://osmocom.org/news/255
Related: OS#6446
Change-Id: I703e115a426ac1012c80d2e1576ee6dcfbe191a5
2024-05-08 14:41:07 +02:00
Pau Espin Pedrol
e01f6e7f33 iuup: Increment RTP hdr seqnr even if Tx over UDP fails
This way holes can be detected. In practice it's not much important
since it would be really strange that UDP fails for a while and then it
starts working out of the blue...

Related: SYS#6907
Change-Id: I8095f3505c859650c0b83abce405067bef745975
2024-04-24 18:57:02 +02:00
Pau Espin Pedrol
388b48d14e Fix IuUP RTP hdr seqnr field not incremented
Previous commit add osmo_io changed mgcp_udp_send() implementation from
"return sendto()", which is documented as:
"return the number of bytes sent. Otherwise, -1 shall be returned"

to "return mgcp_udp_send_msg()", which in turn calls
"return osmo_iofd_sendto_msgb()", and which is documented as:
"\returns 0 in case of success (takes msgb ownership), -1 on error
(doesn't take msgb ownership)."

So successful return code changed from >0 (bytes sent) to ==0,
but forgot to update mgcp_send_iuup() return code path check (and also
some related function documentation calling mgcp_udp_send()".

This commit fixes all the related aspects of that return code change.

Related: SYS#6907
Fixes: 352b967d1b
Change-Id: I154e1e41cd02fd4d9b88ad98fc7c4d657246c589
2024-04-24 18:56:57 +02:00
Harald Welte
352b967d1b 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-04-02 19:40:03 +02:00
Harald Welte
ed4da25f2f cosmetic: make linter happy
Change-Id: Iec8404061588b848f9e597bf4112d6df9597de95
2024-03-20 14:25:49 +01:00
Harald Welte
5abda312ed 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 14:25:49 +01:00
Harald Welte
75862d3131 remove osmo_fd from mgcp_create_bind()
preparation for osmo_io

Change-Id: I4a3b66a14fdfbc867daca0f0a05f694d5e0d7b66
2024-03-20 14:25:49 +01:00
Harald Welte
8733542b13 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-20 14:25:43 +01:00
Harald Welte
d7aac20cc1 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-20 13:25:22 +00:00
Harald Welte
8b5361412c 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-20 12:34:38 +00:00
23 changed files with 886 additions and 598 deletions

View File

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

View File

@@ -1,41 +1,11 @@
# 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)
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
# LIBVERSION=c:r:a
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
libosmocore bump_dep; workaround Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.

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.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)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.6.0)
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
@@ -204,5 +204,4 @@ AC_OUTPUT(
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-mgw.spec
Makefile)

View File

@@ -1,122 +0,0 @@
#
# spec file for package osmo-mgw
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: osmo-mgw
Version: @VERSION@
Release: 0
Summary: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
License: AGPL-3.0-or-later AND GPL-2.0-or-later
Group: Hardware/Mobile
URL: https://osmocom.org/projects/osmo-mgw
Source: %{name}-%{version}.tar.xz
BuildRequires: automake >= 1.9
BuildRequires: libtool >= 2
BuildRequires: pkgconfig >= 0.20
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libosmo-netif) >= 1.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,8 +9,11 @@ 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):

91
debian/changelog vendored
View File

@@ -1,3 +1,94 @@
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.9.0),
libosmo-netif-dev (>= 1.4.0),
libosmo-abis-dev (>= 1.5.0),
osmo-gsm-manuals-dev (>= 1.5.0)
libosmocore-dev (>= 1.10.0),
libosmo-netif-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.6.0),
osmo-gsm-manuals-dev (>= 1.6.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-client12
Package: libosmo-mgcp-client14
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-client12 (= ${binary:Version}), ${misc:Depends}
Depends: libosmo-mgcp-client14 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: osmo-mgw-doc

38
debian/postinst vendored Executable file
View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/mgcp/mgcp.h>
@@ -93,7 +94,7 @@ struct mgcp_rtp_end {
struct osmo_sockaddr addr;
/* in network byte order */
int rtcp_port;
uint16_t rtcp_port;
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
@@ -120,8 +121,8 @@ struct mgcp_rtp_end {
bool rfc5993_hr_convert;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_fd rtp;
struct osmo_fd rtcp;
struct osmo_io_fd *rtp;
struct osmo_io_fd *rtcp;
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
@@ -159,8 +160,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn_dst,
@@ -180,7 +180,7 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
int id, int inc);
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id);
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
uint32_t mgcp_get_current_ts(unsigned codec_rate);
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);

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=13:0:1
MGCP_CLIENT_LIBVERSION=14:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \

View File

@@ -1315,6 +1315,7 @@ 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;
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
@@ -1366,17 +1367,19 @@ 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 */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT) {
if (mgcp_msg->audio_port == 0) {
audio_port = 0;
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)) {
audio_port = mgcp_msg->audio_port;
if (!audio_port) {
LOGPMGW(mgcp, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
return -EINVAL;
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", 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

@@ -106,8 +106,8 @@ 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.fd = -1;
end->rtcp.fd = -1;
end->rtp = NULL;
end->rtcp = NULL;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;

View File

@@ -301,7 +301,6 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
msgb_free(msg);
return;
skip:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
@@ -325,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 */
msgb_enqueue(&ts->raw.tx_queue, msg);
e1inp_ts_send_raw(ts, msg);
return;
}
@@ -466,11 +465,21 @@ 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;
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU16_FT_EFR;
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
return OSMO_TRAU16_FT_HR;
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
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) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -488,11 +497,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 */
@@ -501,11 +510,21 @@ 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;
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
return OSMO_TRAU_SYNCP_16_FR_EFR;
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 (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) {
if (i460_rate == OSMO_I460_RATE_8k) {
switch (amr_ft) {
case AMR_4_75:
@@ -523,11 +542,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 */

View File

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

View File

@@ -4,6 +4,7 @@
/*
* (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
@@ -70,6 +71,18 @@ void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
}
/* wrapper around libosmocore msgb_copy_c, which [at least before libosmocore.git Change-Id
* I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5] doesn't copy the cb */
static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const char *name)
{
struct msgb *msg2 = msgb_copy_c(ctx, msg, name);
if (OSMO_UNLIKELY(!msg2))
return NULL;
memcpy(msg2->cb, msg->cb, sizeof(msg2->cb));
return msg2;
}
static int rx_rtp(struct msgb *msg);
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
@@ -404,15 +417,12 @@ static int align_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
* \param[in] associated endpoint.
* \param[in] destination RTP end.
* \param[in,out] pointer to buffer with voice data.
* \param[in] voice data length.
* \param[in] maximum size of caller provided voice data buffer.
* \param[in,out] msg message bufffer containing data. Function might change length.
* \returns ignores input parameters, return always 0. */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size)
struct msgb *msg)
{
LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
return 0;
}
@@ -785,16 +795,18 @@ static int amr_oa_check(char *data, int len)
/* Forward data to a debug tap. This is debug function that is intended for
* debugging the voice traffic with tools like gstreamer */
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg)
{
int rc;
if (!tap->enabled)
return;
rc = sendto(fd, msgb_data(msg), msgb_length(msg), 0, (struct sockaddr *)&tap->forward,
sizeof(tap->forward));
struct msgb *msg2 = msgb_copy(msg, "RTP TAP Tx");
if (!msg2)
return;
rc = osmo_iofd_sendto_msgb(iofd, msg2, 0, &tap->forward);
if (rc < 0)
LOGP(DRTP, LOGL_ERROR,
"Forwarding tapped (debug) voice data failed.\n");
@@ -966,7 +978,7 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
return 0;
}
/*! Dispatch msg bridged from the sister conn in the endpoint.
/*! Dispatch msg bridged from the sister conn in the endpoint. Takes ownership of msgb.
* \param[in] conn_dst The destination conn that should handle and transmit the content to
* its peer outside MGW.
* \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
@@ -988,8 +1000,10 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
/* Before we try to deliver the packet, we check if the destination
* port and IP-Address make sense at all. If not, we will be unable
* to deliver the packet. */
if (check_rtp_destin(conn_dst) != 0)
if (check_rtp_destin(conn_dst) != 0) {
msgb_free(msg);
return -1;
}
/* Depending on the RTP connection type, deliver the RTP packet to the
* destination connection. */
@@ -1024,39 +1038,46 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
* be discarded, this should not happen, normally the MGCP type
* should be properly set */
LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
msgb_free(msg);
return -1;
}
/*! send udp packet.
* \param[in] fd associated file descriptor.
/*! send message buffer via udp socket. If it succeeds, it takes ownership of the msgb and internally calls
* msgb_free() after the aynchronous sendto() completes. In case of error, the msgb is still owned by the
* caller and must be free'd accordingly.
* \param[in] iofd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] msg message buffer that holds the data to be send.
* \returns 0 in case of success (takes msgb ownership), -1 on error (doesn't take msgb ownership). */
static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, struct msgb *msg)
{
LOGP(DRTP, LOGL_DEBUG, "sending %d bytes length packet to %s ...\n", msgb_length(msg),
osmo_sockaddr_to_str(addr));
return osmo_iofd_sendto_msgb(iofd, msg, 0, addr);
}
/*! send udp packet from raw buffer/length.
* \param[in] iofd associated file descriptor.
* \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 bytes sent, -1 on error. */
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
* \returns 0 in case of success, -1 on error. */
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len)
{
char ipbuf[INET6_ADDRSTRLEN];
size_t addr_len;
struct msgb *msg = msgb_alloc_c(iofd, len, "mgcp_udp_send");
if (!msg)
return -ENOMEM;
memcpy(msg->tail, buf, len);
msgb_put(msg, len);
LOGP(DRTP, LOGL_DEBUG,
"sending %i bytes length packet to %s:%u ...\n", len,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
osmo_sockaddr_port(&addr->u.sa));
if (addr->u.sa.sa_family == AF_INET6) {
addr_len = sizeof(addr->u.sin6);
} else {
addr_len = sizeof(addr->u.sin);
}
return sendto(fd, buf, len, 0, &addr->u.sa, addr_len);
return mgcp_udp_send_msg(iofd, addr, msg);
}
/*! 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 bytes sent, -1 on error. */
* \returns 0 in case of success, -1 on error. */
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int rc;
@@ -1078,8 +1099,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
if (mgcp_conn_rtp_is_iuup(conn))
rc = mgcp_conn_iuup_send_dummy(conn);
else
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
rc = mgcp_udp_send(conn->end.rtp, &conn->end.addr, rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
goto failed;
@@ -1090,10 +1110,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
was_rtcp = 1;
rtcp_addr = conn->end.addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
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:
@@ -1104,7 +1124,7 @@ failed:
return -1;
}
/*! Send RTP/RTCP data to a specified destination connection.
/*! Send RTP/RTCP data to a specified destination connection. Takes ownership of msg.
* \param[in] endp associated endpoint (for configuration, logging).
* \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
* \param[in] addr spoofed source address (set to NULL to disable).
@@ -1143,6 +1163,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
if (mgcp_patch_pt(conn_dst, msg) < 0) {
LOGPENDP(endp, DRTP, LOGL_NOTICE, "unable to patch payload type RTP packet, discarding...\n");
msgb_free(msg);
return -EINVAL;
}
}
@@ -1168,73 +1189,69 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
int cont;
int nbytes = 0;
int buflen = msgb_length(msg);
/* Make sure we have a valid RTP header, in cases where no RTP
* header is present, we will generate one. */
gen_rtp_header(msg, rtp_end, rtp_state);
do {
/* Run transcoder */
cont = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, (char *)msgb_data(msg), &buflen, RTP_BUF_SIZE);
if (cont < 0)
break;
/* Run transcoder */
rc = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error %d during transcoding\n", rc);
msgb_free(msg);
return rc;
}
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
break;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
break;
}
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
msgb_free(msg);
return rc;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
msgb_free(msg);
return rc;
}
}
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
(char *)msgb_data(msg), msgb_length(msg));
len = msgb_length(msg);
if (len <= 0)
return len;
rc = mgcp_udp_send_msg(rtp_end->rtp, &rtp_end->addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
nbytes += len;
buflen = cont;
} while (buflen > 0);
return nbytes;
return 0;
} else if (!trunk->omit_rtcp) {
struct osmo_sockaddr rtcp_addr = rtp_end->addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(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),
@@ -1242,19 +1259,54 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtcp_addr.u.sa)
);
len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
(char *)msgb_data(msg), msgb_length(msg));
len = msgb_length(msg);
rc = mgcp_udp_send_msg(rtp_end->rtcp, &rtcp_addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return len;
return 0;
}
msgb_free(msg);
return 0;
}
/*! determine if there's only a single recipient in endp for data received via conn_src.
* The function returns NULL in case there is no recipient, or in case there are multiple recipients.
* \param endp The MGCP endpoint whose connections to analyze
* \param conn_src The source MGCP connection [which shall not count in results]
* \returns recipient donnection if there is only one; NULL in case there are multiple */
static struct mgcp_conn *rtpbridge_get_only_recipient(struct mgcp_endpoint *endp, struct mgcp_conn *conn_src)
{
struct mgcp_conn *conn_ret = NULL;
struct mgcp_conn *conn_dst;
llist_for_each_entry(conn_dst, &endp->conns, entry) {
if (conn_dst == conn_src)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
if (conn_ret)
return NULL;
conn_ret = conn_dst;
break;
default:
break;
}
}
return conn_ret;
}
/*! Dispatch incoming RTP packet to opposite RTP connection.
* \param[in] msg Message buffer to bridge, coming from source connection.
* msg shall contain "struct osmo_rtp_msg_ctx *" attached in
@@ -1312,23 +1364,44 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
return rc;
}
/* If the mode is "confecho", send RTP back to the sender. */
if (conn->mode == MGCP_CONN_CONFECHO)
rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
/* All the use cases above are 1:1 where we have one source msgb and we're sending that to one
* destination. msgb ownership had been passed to the respective _*dospatch_rtp() function.
* In the cases below, we actually [can] have multiple recipients, so we copy the original msgb
* for each of the recipients. */
/* Dispatch RTP packet to all other connection(s) that send audio. */
llist_for_each_entry(conn_dst, &endp->conns, entry) {
if (conn_dst == conn)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
break;
default:
break;
/* If the mode is "confecho", send RTP back to the sender. */
if (conn->mode == MGCP_CONN_CONFECHO) {
struct msgb *msg2 = mgw_msgb_copy_c(conn, msg, "RTP confecho");
if (OSMO_LIKELY(msg2))
rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg2);
}
conn_dst = rtpbridge_get_only_recipient(endp, conn);
if (OSMO_LIKELY(conn_dst)) {
/* we only have a single recipient and cann hence send the original msgb without copying */
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
} else {
/* Dispatch RTP packet to all other connection(s) that send audio. */
llist_for_each_entry(conn_dst, &endp->conns, entry) {
struct msgb *msg2;
if (conn_dst == conn)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
/* we have multiple recipients and must make copies for each recipient */
msg2 = mgw_msgb_copy_c(conn_dst, msg, "RTP Tx copy");
if (OSMO_LIKELY(msg2))
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg2);
break;
default:
break;
}
}
/* as we only sent copies in the previous llist_for_each_entry() loop, we must free the
* original one */
msgb_free(msg);
}
return rc;
}
@@ -1400,7 +1473,7 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
}
/* Handle incoming RTP data from NET */
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *saddr)
{
/* NOTE: This is a generic implementation. RTP data is received. In
* case of loopback the data is just sent back to its origin. All
@@ -1411,49 +1484,34 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
struct mgcp_conn_rtp *conn_src;
struct mgcp_endpoint *endp;
struct osmo_sockaddr addr;
socklen_t slen = sizeof(addr);
char ipbuf[INET6_ADDRSTRLEN];
int ret;
enum rtp_proto proto;
struct osmo_rtp_msg_ctx *mc;
struct msgb *msg;
int rc;
conn_src = (struct mgcp_conn_rtp *)fd->data;
conn_src = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
OSMO_ASSERT(conn_src);
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx");
proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
proto = (iofd == conn_src->end.rtp) ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
ret = recvfrom(fd->fd, msgb_data(msg), msg->data_len, 0, (struct sockaddr *)&addr.u.sa, &slen);
if (ret <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
rc = -1;
goto out;
if (res <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(-res));
goto out_free;
}
msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
osmo_sockaddr_port(&addr.u.sa));
msgb_length(msg), osmo_sockaddr_to_str(saddr));
if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
|| (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
/* Logging happened in the two check_ functions */
rc = -1;
goto out;
goto out_free;
}
if (mgcp_is_rtp_dummy_payload(msg)) {
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
rc = 0;
goto out;
goto out_free;
}
/* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
@@ -1462,7 +1520,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
*mc = (struct osmo_rtp_msg_ctx){
.proto = proto,
.conn_src = conn_src,
.from_addr = &addr,
.from_addr = (struct osmo_sockaddr *) saddr,
};
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
mc->proto, mc->conn_src,
@@ -1477,16 +1535,17 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(fd->fd, &conn_src->tap_in, msg);
forward_data_tap(iofd, &conn_src->tap_in, msg);
rc = rx_rtp(msg);
rx_rtp(msg);
return;
out:
out_free:
msgb_free(msg);
return rc;
}
/* Note: This function is able to handle RTP and RTCP */
/* Note: This function is able to handle RTP and RTCP. msgb ownership is transferred, so this function or its
* downstream consumers must make sure to [eventually] free the msgb. */
static int rx_rtp(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
@@ -1499,7 +1558,7 @@ static int rx_rtp(struct msgb *msg)
/* Check if the origin of the RTP packet seems plausible */
if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
return -1;
goto out_free;
/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
if (mc->proto == MGCP_PROTO_RTP
@@ -1509,13 +1568,13 @@ static int rx_rtp(struct msgb *msg)
* communicated via SDP when the connection was created/modfied. */
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
return -1;
goto out_free;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
return -1;
goto out_free;
}
}
@@ -1524,17 +1583,36 @@ static int rx_rtp(struct msgb *msg)
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
return conn->endp->type->dispatch_rtp_cb(msg);
out_free:
msgb_free(msg);
return -1;
}
static void rtp_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *daddr)
{
/* nothing; osmo_io takes care of msgb_free */
if (res < 0) {
struct mgcp_conn_rtp *conn_rtp = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
int priv_nr = osmo_iofd_get_priv_nr(iofd);
char errbuf[129];
strerror_r(-res, errbuf, sizeof(errbuf));
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
osmo_sockaddr_to_str(daddr), errbuf);
}
}
static const struct osmo_io_ops rtp_ioops = {
.recvfrom_cb = rtp_recvfrom_cb,
.sendto_cb = rtp_sendto_cb,
};
/*! bind RTP port to osmo_fd.
* \param[in] source_addr source (local) address to bind on.
* \param[in] fd associated file descriptor.
* \param[in] port to bind on.
* \param[in] dscp IP DSCP value to use.
* \param[in] prio socket priority to use.
* \returns 0 on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio)
* \returns file descriptor on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio)
{
int rc;
@@ -1542,47 +1620,50 @@ int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint
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:%i).\n",
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%d).\n",
source_addr, port);
return -1;
}
fd->fd = rc;
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%d).\n", source_addr, port);
return 0;
return rc;
}
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
int rc, rtp_fd, rtcp_fd;
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
if (mgcp_create_bind(source_addr, &rtp_end->rtp, rtp_end->local_port,
cfg->endp_dscp, cfg->endp_priority) != 0) {
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;
if (mgcp_create_bind(source_addr, &rtp_end->rtcp, rtp_end->local_port + 1,
cfg->endp_dscp, cfg->endp_priority) != 0) {
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_fd_register(&rtp_end->rtp) != 0) {
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_fd_register(&rtp_end->rtcp) != 0) {
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);
@@ -1592,13 +1673,11 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
return 0;
cleanup3:
osmo_fd_unregister(&rtp_end->rtp);
osmo_iofd_unregister(rtp_end->rtp);
cleanup2:
close(rtp_end->rtcp.fd);
rtp_end->rtcp.fd = -1;
close(rtcp_fd);
cleanup1:
close(rtp_end->rtp.fd);
rtp_end->rtp.fd = -1;
close(rtp_fd);
cleanup0:
return -1;
}
@@ -1617,7 +1696,8 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
(end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
rtp_port, mgcp_conn_dump(conn->conn));
@@ -1630,8 +1710,18 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
}
end->local_port = rtp_port;
osmo_fd_setup(&end->rtp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
osmo_fd_setup(&end->rtcp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtp)
return -EIO;
osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtcp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
}
osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
}
@@ -1640,15 +1730,13 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
* \param[in] end RTP end */
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp.fd != -1) {
osmo_fd_unregister(&end->rtp);
close(end->rtp.fd);
end->rtp.fd = -1;
if (end->rtp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
}
if (end->rtcp.fd != -1) {
osmo_fd_unregister(&end->rtcp);
close(end->rtcp.fd);
end->rtcp.fd = -1;
if (end->rtcp) {
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
}
}

View File

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

View File

@@ -1083,17 +1083,6 @@ mgcp_header_done:
mgcp_rtp_end_config(endp, 0, &conn->end);
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
"CRCX: selected connection mode type requires an opposite end!\n");
error_code = 527;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC));
goto error2;
}
/* Find a local address for conn based on policy and initial SDP remote
information, then find a free port for it */
if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
@@ -1295,17 +1284,6 @@ mgcp_header_done:
if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0)
rc = mgcp_conn_iuup_init(conn);
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& !mgcp_rtp_end_remote_addr_available(&conn->end)) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: selected connection mode type requires an opposite end!\n");
error_code = 527;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC));
goto error3;
}
if (mgcp_conn_rtp_is_osmux(conn)) {
OSMO_ASSERT(conn->osmux.local_cid_allocated);
if (remote_osmux_cid < -1) {

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:40\r\n"
"a=ptime:20\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
@@ -127,40 +127,49 @@ 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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_ADDR0000 \
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_ADDR0000_RET \
"527 18983216 FAIL\r\n"
"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"
#define MDCX4 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -172,7 +181,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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -184,87 +193,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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_PT1 \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: SENDRECV\r" \
"M: SENDRECV\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_PT2 \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_PT3 \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
/* Test different upper/lower case in options */
#define MDCX4_PT4 \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"m: sendrecv\r" \
"m: sendrecv\r\n" \
"c: 2\r\n" \
"i: %s\r\n" \
"l: A:amr, NT:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_SO \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r" \
"M: sendonly\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"\r\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:40\r\n"
"a=ptime:20\r\n"
#define MDCX4_RO \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
@@ -297,7 +306,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_RET \
"200 2 OK\r\n" \
@@ -310,7 +319,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
@@ -322,7 +331,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
@@ -335,17 +344,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_ZYN \
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"C: 2\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"
"\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"
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
@@ -371,7 +380,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_X_OSMO_IGN_RET \
"200 2 OK\r\n" \
@@ -384,7 +393,95 @@ 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:40\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"
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
@@ -441,7 +538,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
@@ -456,7 +553,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
@@ -471,7 +568,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
@@ -486,7 +583,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
@@ -575,7 +672,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:40\r\n"
"a=ptime:20\r\n"
#define CRCX_NULL_RET "502 2 FAIL\r\n"
@@ -623,6 +720,11 @@ 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[] = {
@@ -653,12 +755,13 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
static int dummy_packets = 0;
/* override and forward */
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
{
uint32_t dest_host =
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
const uint8_t *buf = msgb_data(msg);
size_t len = msgb_length(msg);
if (len == sizeof(rtp_dummy_payload)
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
@@ -672,6 +775,8 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
OSMO_ASSERT(dest_host);
OSMO_ASSERT(dest_port);
msgb_free(msg);
return len;
}
@@ -1103,7 +1208,9 @@ static void test_packet_loss_calc(void)
_conn =
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
state = &conn->state;
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);

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:40
a=ptime:20
---------8<---------
checking response:
@@ -101,40 +101,42 @@ Testing MDCX4_ADDR000
creating message from statically defined input:
---------8<---------
MDCX 18983216 1@mgw MGCP 1.0
M: sendrecv
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
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=rtpmap:99 AMR/8000
a=rtpmap:99 AMR/8000
a=ptime:20
---------8<---------
checking response:
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
Response matches our expectations.
(response contains a connection id)
================================================
Testing MDCX4
creating message from statically defined input:
---------8<---------
MDCX 18983217 1@mgw MGCP 1.0
MDCX 18983217 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
I: %s
v=0
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
a=rtpmap:99 AMR/8000
m=audio 4441 RTP/AVP 99
a=ptime:20
---------8<---------
checking response:
@@ -148,17 +150,18 @@ Testing MDCX4_PT1
creating message from statically defined input:
---------8<---------
MDCX 18983218 1@mgw MGCP 1.0
---------8<---------
M: SENDRECV
C: 2
I: %s
L: p:20-40, a:AMR, nt:IN
C: 2
v=0
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
a=rtpmap:99 AMR/8000
t=0 0
a=ptime:20
---------8<---------
checking response:
@@ -172,17 +175,18 @@ Testing MDCX4_PT2
creating message from statically defined input:
---------8<---------
MDCX 18983219 1@mgw MGCP 1.0
creating message from statically defined input:
M: sendrecv
C: 2
I: %s
L: p:20-20, a:AMR, nt:IN
M: sendrecv
v=0
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
a=rtpmap:99 AMR/8000
c=IN IP4 5.6.7.8
a=ptime:20
---------8<---------
checking response:
@@ -196,17 +200,18 @@ Testing MDCX4_PT3
creating message from statically defined input:
---------8<---------
MDCX 18983220 1@mgw MGCP 1.0
Testing MDCX4_PT3
M: sendrecv
C: 2
I: %s
L: a:AMR, nt:IN
MDCX 18983220 1@mgw MGCP 1.0
v=0
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
a=rtpmap:99 AMR/8000
o=- %s 23 IN IP4 5.6.7.8
a=ptime:20
---------8<---------
checking response:
@@ -220,17 +225,18 @@ 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
---------8<---------
v=0
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
a=rtpmap:99 AMR/8000
v=0
a=ptime:20
---------8<---------
checking response:
@@ -244,17 +250,18 @@ 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
creating message from statically defined input:
v=0
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
a=rtpmap:99 AMR/8000
a=ptime:20
---------8<---------
checking response:
@@ -267,7 +274,8 @@ Testing MDCX4_RO
creating message from statically defined input:
---------8<---------
MDCX 18983223 1@mgw MGCP 1.0
(response contains a connection id)
M: recvonly
C: 2
I: %s
L: p:20, a:AMR, nt:IN
@@ -296,9 +304,15 @@ Response matches our expectations.
Testing CRCX_ZYN
creating message from statically defined input:
---------8<---------
using message as statically defined for comparison
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
(response does not contain a connection id)
---------8<---------
checking response:
using message with patched conn_id for comparison
@@ -414,7 +428,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
---------8<---------
checking response:
@@ -479,7 +493,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
Testing CRCX
a=ptime:20
---------8<---------
checking response:
@@ -550,7 +564,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
---------8<---------
checking response:
@@ -599,6 +613,110 @@ using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX_PORT_0
creating message from statically defined input:
---------8<---------
CRCX 3 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
M: sendrecv
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV2
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
a=sendrecv
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX_PORT_0_IUFP_SENDRECV3
creating message from statically defined input:
---------8<---------
CRCX 4 1@mgw MGCP 1.0
C: 2
L: p:20
v=0
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
================================================
Testing CRCX
creating message from statically defined input:
@@ -612,7 +730,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
---------8<---------
checking response:
@@ -630,7 +748,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
Response matches our expectations.
a=ptime:20
---------8<---------
checking response:
@@ -742,7 +860,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
Response matches our expectations.
a=ptime:20
---------8<---------
creating message from statically defined input:
@@ -1196,7 +1314,7 @@ c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 18 97
a=rtpmap:18 G729/8000
a=rtpmap:97 GSM-EFR/8000
creating message from statically defined input:
a=ptime:20
---------8<---------
creating message from statically defined input:
@@ -1213,7 +1331,7 @@ m=audio 5904 RTP/AVP 18 97 101
a=rtpmap:18 G729/8000
a=rtpmap:97 GSM-EFR/8000
a=rtpmap:101 FOO/8000
---------8<---------
a=ptime:20
---------8<---------
creating message from statically defined input:
@@ -1230,7 +1348,7 @@ m=audio 5904 RTP/AVP
a=rtpmap:18 G729/8000
a=rtpmap:97 GSM-EFR/8000
a=rtpmap:101 FOO/8000
---------8<---------
a=ptime:20
---------8<---------
creating message from statically defined input:
@@ -1247,7 +1365,7 @@ m=audio 5904 RTP/AVP 18
a=rtpmap:18 G729/8000
a=rtpmap:97 GSM-EFR/8000
a=rtpmap:101 FOO/8000
---------8<---------
a=ptime:20
---------8<---------
creating message from statically defined input:
@@ -1329,7 +1447,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
Testing no sequence flow on initial packet
a=ptime:20
---------8<---------
checking response: