Compare commits

..

28 Commits

Author SHA1 Message Date
Neels Hofmeyr
c3a7b6b085 fix SDP codecs lists returned in OK messages
So far, osmo-mgw picked a single codec per side and returned only that
entry in the SDP part of MGCP 'OK' responses.

Instead, return all of the codec entries that were successfully
assigned.

The difference is shown in mgcp_test.c: before, only one of the codecs
made it through to the 'OK' reponse. Now, all of them are reflected
properly.

To clients that only ever assign a single codec, there is no change in
behavior.

Simplify the code: collapse these functions
  add_rtpmap()
  add_fmtp()
  add_audio()
  codec related part from mgcp_write_response_sdp()
and have only
  add_codecs()
add_codecs() simply iterates all assigned codecs to output the 'm=audio'
line as well as any 'a=rtpmap' and 'a=fmtp' lines.

Also helping to simplify is that we recently dropped the 'fmtp-extra'
feature in Icee0cd1f5a751fa760d5a9deca29089e78e7eb93

Related: OS#6293
Change-Id: Ib197ae30a4e732e7dc36700ba8b5841806ea12f7
2023-12-23 06:59:35 +01:00
Neels Hofmeyr
850a7c3b5a mgcp_test.c: test responses for multiple payloads
There are tests with multiple payloads in test_multiple_codec(), but
they do not verify the responses that osmo-mgw returns. Just add a
couple of entries to test_messages().

Change-Id: I604b81d9887eb63dab584a524b8f4eeb821e2c78
2023-12-23 06:59:35 +01:00
Neels Hofmeyr
ae6042e773 dbg: show conns on CRCX/MDCX
Change-Id: I8f50edfc6100ccb88fe9c35592be820f76bd256b
2023-12-23 06:59:35 +01:00
Neels Hofmeyr
5d9036176d mgcp_conn_dump(): include assigned codecs
Change-Id: I6c9234467e26e2b7e6a41ecf079cc0799f6b5dac
2023-12-23 06:59:35 +01:00
Neels Hofmeyr
553b123a97 mgcp_test.c: fflush
Change-Id: I6a30aeda4c139b52982faeabb3492991a8ff88ac
2023-12-23 06:59:35 +01:00
Neels Hofmeyr
cb4a296a21 mgcp_test.c: tweak output, comment
Change-Id: If5187d1d79fba78e19800822a5964d1c08c2fcfa
2023-12-23 06:59:25 +01:00
Neels Hofmeyr
7f158600ce dbg: log MGCP retransmission
Change-Id: I3920364a7573411c8d6a1d64721064f720ae1280
2023-12-23 06:10:23 +01:00
Neels Hofmeyr
ca3d664d08 dbg: mgcp_codec_decide(): log codecs
Change-Id: Ic24184d99a042970ac8e314bb020276fd2bc55c5
2023-12-23 06:10:17 +01:00
Neels Hofmeyr
146a370412 mgcp_test.c: show all DLMGCP logging
Change-Id: I7fde39bb368c0f2926b1147753fa5d925c354a21
2023-12-23 06:03:37 +01:00
Neels Hofmeyr
1cbf8495c7 drop cfg 'sdp audio fmtp-extra'
There is considerable code complexity in place for this ancient hack.

It dates back to 5ea1bc77a3
"
mgcp: Allow to freely control the a=fmtp line for experiments

In case of AMR one can specify the available codecs out-of-band. Allow
to configure this line statically in the configuration file.
"

Looking in mgcp_test.c output, the fmtp-extra tests do not even make
sense: they result in fmtp for pt=126 being added, even though there is
no payload type 126 listed in the SDP...

Related: OS#6313
Change-Id: Icee0cd1f5a751fa760d5a9deca29089e78e7eb93
2023-12-23 04:00:10 +01:00
Neels Hofmeyr
7ee24139a5 drop get_net_downlink_format_cb
It seems to be a remnant from early openbsc_mgcp. There is only the
default implementation for this callback and it simply returns two
pointers. Simplify that.

Change-Id: I18dfd44c931540caf4ac360c08ed10e5f65b2165
2023-12-23 03:58:19 +01:00
Neels Hofmeyr
febbf7d337 tests/mgcp: add update_exp target
Change-Id: I1ea7e881fe13429762bf31507d8d23fe58e241b3
2023-12-23 03:57:55 +01:00
Neels Hofmeyr
fc17517e9e tweak DEBUG log
Printing the debug log line a little later will include the MGCP verb
information.

Change-Id: Icb230cf4d623cdbc4ab52bd52d2a72525c0168c7
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
d2634027cf mgcp_test: fix false negatives in test output
If one test fails, do not print failure for all following tests as well.

Change-Id: I196880b4b34a672ef45042c25f89bc1684363567
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
5fbe450e64 mgw: do not fail MGCP on codec mismatch
Before this patch, when an CRCX+MDCX wants to set a codec list that has
no match with the codecs for the other conn of that same endpoint,
osmo-mgw returns an MGCP "FAIL" response.

When a client wants to change the codec, it has to do that one RTP port
at a time. So osmo-mgw *must* allow to configure an MGCP conn with a
codec choice that mismatches the other conn.

This is crucial to allow codec negotiation in osmo-msc: if MO has
already assigned a specific codec, and later wants to re-assign to the
codec that MT has chosen, the codec needs to be changed at osmo-mgw.

This patch is the minimal fix required to get re-assignment to a
different codec to work (via osmo-msc). There is more work to be done
about this bit of code in osmo-mgw, but keep that to a separate patch.

In detail, before this patch, we fail both
- when a side has no codecs,
- or when there is no single match between codecs of the two sides of
  the endpoint.
Remove only the second condition; after this patch, still fail when a
side has no codecs -- this allows mgcp_test.c to still pass.

Related: OS#6293
Related: osmo-msc I8760feaa8598047369ef8c3ab2673013bac8ac8a
Change-Id: I3d1163fe622bdd7dc42a485f796072524ab39db9
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
6fe0ed2bb4 mgcp_codec_decide: remove redundant lookup
We already did a lookup from conn_src[i] and found a matching
codec_conn_dst, no need to do another reverse lookup to end up at the
same conn_src[i] codec.

Change-Id: Iecc7f22c551fd17b23db434fdb177266407d2621
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
0b4d5c0d82 mgcp-client: MGCP response: pass fmtp to caller
When receiving MGCP responses, so far libosmo-mgcp-client completely
ignored a=fmtp: parameters (like 'octet-align'). Add fmtp parsing to
pass the fmtp string to the caller as-is.

Since the responses so far never included the octet_aligned flags, do
not bother to parse fmtp to populate the legacy items. New callers
should use the fmtp string.

Change-Id: If8ca5c3880cad9e41b80e9d1c821439b0d7b7e23
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
e220fa10d3 mgw, client: add fmtp string to ptmap: allow all possible fmtp
Remove the limit of having only one AMR octet-aligned fmtp parameter per
MGCP message. Instead allow any arbitrary fmtp options, one per every
codec.

Deprecate all use of struct mgcp_codec_param. Instead, store and pass
plain fmtp strings.

Provide legacy shims that still act correctly for any callers that may
pass the old struct mgcp_codec_param. (I'm not sure if we need to keep
this, but we can always drop it in another patch.)

Adjust one mgcp_test.c: instead of returning only the octet-aligned
parameter, now osmo-mgw keeps and returns all the fmtp parameters that
the user provided. So add the missing "mode-change-capability".

Related: OS#6171
Related: osmo-msc Ief9225c9bcf7525a9a0a07c282ffb8cc0d092186
Change-Id: If58590bda8627519ff07e0b6f43aa47a274f052b
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
527a45bc67 add fmtp.h
Upcoming patches will add handling of arbitrary ftmp strings to
osmo-mgw as well as libosmo-mgcp-client
(If58590bda8627519ff07e0b6f43aa47a274f052b).

Add generic API for handling ftmp strings. The primary intended user is
osmo-mgw, but this is also generally useful to libosmo-mgcp-client
callers for parsing the received fmtp.

We discussed that fmtp.[hc] should be published in libosmo-mgcp-client,
but also built within osmo-mgw. Hence:
- put fmtp.h and .c in libosmo-mgcp-client/
- in osmo-mgw code, use #include <mgcp_client/fmtp.h> and build the
  src/libosmo-mgcp-client/fmtp.c also into libosmo-mgcp.a.

(This is currently the quickest solution and without side effects since
fmtp.c is fully self-contained; an alternative would be adding a
not-installed libmgcp-common.a within the build tree)

Change-Id: I3eaea353dbd98c19212199b564342d0ac16cbc07
2023-12-22 05:34:43 +01:00
Neels Hofmeyr
7365685f47 build: move mgcp/*.h to noinst_HEADERS, drop RPM libosmo-mgcp-devel
We only install the mgcp_client/ headers.

Related: OS#6300
Change-Id: Ie0f79222bd1702097c12193dcf7a0462805cfc4a
2023-12-22 03:04:53 +01:00
Philipp Maier
3f940e5812 mgcp_client_fsm: explain member param in struct mgcp_conn_peer better
The struct member param specifies additional codec parameters. Let's
improve its explaination.

Change-Id: Iea4dc1e72fccaa464ce503fae88b5d8a867b1d19
Related: OS#6171
2023-12-22 03:04:53 +01:00
Philipp Maier
ce37944ce4 mgcp_client_fsm: allocate struct mgcp_conn_peer dynamically
The struct mgcp_conn_peer is allocated statically at the moment. This is
an ABI compatibility in case the struct changes.

Add an alloc function for this struct that API users can use, and
indicate its use in a comment on struct mgcp_conn_peer.

It is not necessary to dynamically allocate the mgcp_conn_peer struct
within libosmo-mgcp-client, because the problem arises only when ABIs
interact. Hence leaving mgcp_client_endpoint_fsm.c's use static.

Related: OS#6171
Change-Id: I523d0fcb020f7d46323c497a4be9ee00d5f242ba
2023-12-22 03:04:53 +01:00
Neels Hofmeyr
77676f2151 drop (now) unused code
Removing the duality of codecs[] and ptmap[] in structs mgcp_msg,
mgcp_response and mgcp_conn_peer has removed the need to "map" from
codec type enum to payload type number. They are stored together now.

Remove functions that are no longer used.
None of our osmocom users of libosmo-mgcp-client call these functions.

Change-Id: I84e5285831397c992af59deee12dea8458d16cc6
2023-12-22 03:04:53 +01:00
Neels Hofmeyr
e8c297248e mgcp_client_test: add test_parse_response()
Change-Id: I842ce65a9a70f313570857b7df53727cc572b9e6
2023-12-22 03:04:45 +01:00
Neels Hofmeyr
3ea1382637 client SDP: more verbose error logging
So far it was pure guess work to find out why a message fails.

Change-Id: Ibc6343db82281789004c140ba98d99e5f6f73d83
2023-12-22 03:03:12 +01:00
Neels Hofmeyr
12d0b04ddc client: allow MGCP_MAX_CODECS entries
So far we allow only MGCP_MAX_CODECS-1 entries, because the parsing exit
condition hits only after the array size check. Instead, check the array
size a bit later, just before actually adding a valid entry.

This is verified to work as expected in upcoming patch
I842ce65a9a70f313570857b7df53727cc572b9e6 that adds a new
mgcp_client_test.c section for this.

Change-Id: I9a28da85e437f118026ea71a5a708e5758fff623
2023-12-22 03:02:40 +01:00
Neels Hofmeyr
b1f7e37847 client: collapse codecs[] and ptmap[]; allow codec variants
codecs[] is an array of enum osmo_mgcp_codecs.
ptmap[] is an array of { enum osmo_mgcp_codecs, unsigned int ptmap }.

MGCP lists first a bunch of payload type numbers and then specifies them
again for details, like the numbers 112, 96, 3 in this example:

 m=audio <port> RTP/AVP 112 96 3
 a=rtpmap:112 AMR/8000
 a=rtpmap:96 VND.3GPP.IUFP/16000
 a=rtpmap:3 GSM-FR/8000

So far we keep these lists in two separate arrays, in both struct
mgcp_response and struct mgcp_msg:
- codecs[], codecs_len stores the 'm=audio' list
- ptmap[], ptmap_len stores the 'a=rtpmap' list (and may omit some
  elements present in codecs[])

These are semantically identical, and the separation means we cannot
have the same codec twice, like AMR with different fmtp variations. It
also leads to checks, conversions and dear hopes of correct ordering.

So let's keep only one list with both codec and payload type number in
it. The 'm=audio' list establishes the order of the pt numbers, and the
'a=rtpmap' list adds codec information to the established entries.

In the internal API structs mgcp_msg and mgcp_response, just drop the
codecs[] entirely.

In public API struct mgcp_conn_peer, keep the codecs[] array, mark it
deprecated, and provide a backwards compat conversion: if any caller
invokes mgcp_conn_create() or mgcp_conn_modify() with codecs[] still
present in the verb_info arg, then move codecs[] entries over to the
ptmap[] array in a sensible way.
(BTW, even mgcp_conn_create() and mgcp_conn_modify() are never called
from outside of libosmo-mgcp-client in any of our osmo-cni programs;
users call osmo_mgcpc_ep_ci_add() and osmo_mgcpc_ep_ci_request(), which
in turn may pass user-provided codecs[] lists on to mgcp_conn_create() or
mgcp_conn_modify().)

Tests for parsing the MGCP response are mostly missing. They will be
added in upcoming patch I842ce65a9a70f313570857b7df53727cc572b9e6,
because they will be using only the new ptmap API.

Related: OS#6171
Change-Id: I798e02c6663376d3d52f4a74fc4b32411ce95bed
2023-12-22 02:56:33 +01:00
Neels Hofmeyr
ffd88eda6e client: deprecate legacy API
Change-Id: I7409907dafbb2fe905fee9bc22d6870056bf3022
2023-12-22 02:53:16 +01:00
57 changed files with 2426 additions and 2742 deletions

View File

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

24
README Normal file
View File

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

102
README.md
View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -9,11 +9,8 @@ LimitNOFILE=65536
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Restart=always
User=osmocom
Group=osmocom
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
RestartSec=2
AmbientCapabilities=CAP_SYS_NICE
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):

140
debian/changelog vendored
View File

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

12
debian/control vendored
View File

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

38
debian/postinst vendored
View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ nobase_include_HEADERS = \
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
osmocom/mgcp_client/mgcp_client_fsm.h \
osmocom/mgcp_client/mgcp_client_pool.h \
osmocom/mgcp_client/fmtp.h \
$(NULL)
noinst_HEADERS = \

View File

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

View File

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

View File

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

View File

@@ -59,7 +59,7 @@ enum mgcp_x_osmo_ign {
MGCP_X_OSMO_IGN_CALLID = 1,
};
/* Codec parameters (communicated via SDP/fmtp) */
/* Deprecated. Use the new fmtp string instead. */
struct mgcp_codec_param {
bool amr_octet_aligned_present;
bool amr_octet_aligned;

View File

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

View File

@@ -138,20 +138,11 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
struct mgcp_config *cfg);
bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
const struct mgcp_trunk *trunk);
void mgcp_endp_release(struct mgcp_endpoint *endp);
struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
const char *id);

View File

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

View File

@@ -4,7 +4,6 @@
#include <stdbool.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/mgcp/mgcp.h>
@@ -74,6 +73,68 @@ struct mgcp_rtp_state {
uint32_t alt_rtp_tx_ssrc;
};
struct mgcp_rtp_codec {
uint32_t rate;
int channels;
uint32_t frame_duration_num;
uint32_t frame_duration_den;
int payload_type;
char audio_name[64];
char subtype_name[64];
/* Deprecated. Use the new fmtp string instead. */
bool param_present;
struct mgcp_codec_param param;
char fmtp[256];
};
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
/* remote IP address of the RTP socket */
struct osmo_sockaddr addr;
/* in network byte order */
int rtcp_port;
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
/* array with assigned audio codecs to choose from (SDP) */
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
/* number of assigned audio codecs (SDP) */
unsigned int codecs_assigned;
/* per endpoint data */
int frames_per_packet;
uint32_t packet_duration_ms;
int maximum_packet_time; /* -1: not set */
/* are we transmitting packets (true) or dropping (false) outbound packets */
bool output_enabled;
/* FIXME: This parameter can be set + printed, but is nowhere used! */
int force_output_ptime;
/* RTP patching */
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
int force_aligned_timing;
bool rfc5993_hr_convert;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_fd rtp;
struct osmo_fd rtcp;
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
/* where the endpoint RTP connection binds to, set during CRCX and
* possibly updated during MDCX */
char local_addr[INET6_ADDRSTRLEN];
};
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
struct mgcp_rtp_tap {
/* is this tap active (1) or not (0) */
int enabled;
@@ -91,7 +152,9 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn);
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
@@ -99,7 +162,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn_dst,
@@ -119,7 +183,7 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
int id, int inc);
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id);
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
uint32_t mgcp_get_current_ts(unsigned codec_rate);
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
#pragma once
#include <stddef.h>
#include <stdbool.h>
#define OSMO_SDP_NAME_A "a"
#define OSMO_SDP_NAME_FMTP "fmtp"
#define OSMO_SDP_NAME_AMR_OCTET_ALIGN "octet-align"
#define OSMO_SDP_VAL_AMR_OCTET_ALIGN_0 OSMO_SDP_NAME_AMR_OCTET_ALIGN "=0"
#define OSMO_SDP_VAL_AMR_OCTET_ALIGN_1 OSMO_SDP_NAME_AMR_OCTET_ALIGN "=1"
/* "fmtp:" */
#define OSMO_SDP_PREFIX_FMTP OSMO_SDP_NAME_FMTP ":"
/* "a=fmtp:" */
#define OSMO_SDP_PREFIX_A_FMTP OSMO_SDP_NAME_A "=" OSMO_SDP_PREFIX_FMTP
bool osmo_sdp_fmtp_get_val(char *val, size_t val_size, const char *fmtp, const char *option_name);
int osmo_sdp_fmtp_get_int(const char *fmtp, const char *option_name, int default_value);
/* Some AMR related fmtp parameters as in https://www.rfc-editor.org/rfc/rfc4867#section-8.1 that osmo-mgw needs.*/
bool osmo_sdp_fmtp_amr_is_octet_aligned(const char *fmtp);
/*! To compose AMR related fmtp indicating octet-align.
* Usage:
* printf("%s", OSMO_SDP_AMR_SET_OCTET_ALIGN(oa_flag));
*/
#define OSMO_SDP_AMR_SET_OCTET_ALIGN(VAL) \
((VAL) ? OSMO_SDP_VAL_AMR_OCTET_ALIGN_1 : OSMO_SDP_VAL_AMR_OCTET_ALIGN_0 )

View File

@@ -77,6 +77,9 @@ struct ptmap {
/*! payload type number (96-127) */
unsigned int pt;
/*! the MGCP 'a=fmtp:N <...>' string, e.g. "mode-set=1,2,3;octet-align=0". */
char fmtp[256];
};
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
@@ -119,9 +122,5 @@ static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
}
enum mgcp_codecs map_str_to_codec(const char *str);
unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
enum mgcp_codecs codec);
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
unsigned int pt);
const char *mgcp_client_name(const struct mgcp_client *mgcp);

View File

@@ -12,7 +12,11 @@
* When modifiying a connection, the endpoint and call_id members may be left
* unpopulated. The call_id field is ignored in this case. If an endpoint
* identifier is supplied it is checked against the internal state to make
* sure it is correct. */
* sure it is correct.
*
* CAUTION: This struct may be subject to changes and new struct members may
* be added in the future. To prevent memory conflicts it is strongly advised
* to allocate this struct dynamically using mgcp_conn_peer_alloc() */
struct mgcp_conn_peer {
/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
char addr[INET6_ADDRSTRLEN];
@@ -57,12 +61,15 @@ struct mgcp_conn_peer {
* address is set. If != MGCP_CONN_NONE, force this conn mode. */
enum mgcp_connection_mode conn_mode;
/*! If the codec requires additional format parameters (fmtp), those cann be set here, see also
* mgcp_common.h */
/*! Deprectated, use ptmap[].fmtp instead.
* Global codec params. In case the codec requires additional format parameters (fmtp), those can be set
* here, see also mgcp_common.h. The format parameters will be applied on all codecs where applicable. */
bool param_present;
struct mgcp_codec_param param;
};
struct mgcp_conn_peer *mgcp_conn_peer_alloc(void *ctx);
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_alloc() and osmo_mgcpc_ep_ci_add() instead");

View File

@@ -1,10 +1,8 @@
#pragma once
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#define MSGB_CB_MGCP_TRANS_ID 0
/* Struct that holds one endpoint name */
@@ -15,7 +13,7 @@ struct reset_ep {
struct mgcp_client {
struct mgcp_client_conf actual;
struct osmo_io_fd *iofd;
struct osmo_wqueue wq;
mgcp_trans_id_t next_trans_id;
struct llist_head responses_pending;
struct mgcp_client_pool_member *pool_member;

View File

@@ -19,7 +19,7 @@ AM_LDFLAGS = \
# This is not at all related to the release version, but a range of supported
# API versions. Read TODO_RELEASE in the source tree's root!
MGCP_CLIENT_LIBVERSION=14:1:0
MGCP_CLIENT_LIBVERSION=13:0:1
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
@@ -31,6 +31,7 @@ libosmo_mgcp_client_la_SOURCES = \
mgcp_client_fsm.c \
mgcp_client_endpoint_fsm.c \
mgcp_client_pool.c \
fmtp.c \
$(NULL)
libosmo_mgcp_client_la_LDFLAGS = \

View File

@@ -0,0 +1,120 @@
/*
* (C) 2023-2015 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <ctype.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/mgcp_client/fmtp.h>
static const char *fmtp_next_option(const char *fmtp)
{
for (; fmtp && *fmtp && *fmtp != ';'; fmtp++);
for (; fmtp && isspace(*fmtp); fmtp++);
return fmtp;
}
/*! Parse a given SDP fmtp value string, returning the value of a specific option, if present.
*
* Example:
*
* const char *fmtp_vals = "octet-align=1;mode-set=0,2,4,7";
*
* char res[23];
* if (osmo_sdp_fmtp_get_val(res, sizeof(res), fmtp_vals, "mode-set"))
* use_modeset(res);
* else
* use_modeset(MY_DEFAULT_MODESET);
*
* \param[out] val Buffer to write the option's value to.
* \param[in] val_size Space available in val.
* \param[in] fmtp fmtp value string to parse -- must not contain the "a=fmtp:N " prefix, only the value part.
* \param[in] option_name Which fmtp option to get the value for.
* \return true when the option was found, false when it was not present.
*/
bool osmo_sdp_fmtp_get_val(char *val, size_t val_size, const char *fmtp, const char *option_name)
{
const char *pos = fmtp;
const char *end;
int option_name_len = strlen(option_name);
for (; pos && *pos; pos = fmtp_next_option(pos)) {
if (!osmo_str_startswith(pos, option_name))
continue;
pos += option_name_len;
if (*pos != '=')
continue;
pos++;
break;
}
if (!pos || !*pos)
return false;
end = fmtp_next_option(pos);
OSMO_ASSERT(end);
if (val && val_size)
osmo_strlcpy(val, pos, OSMO_MIN(val_size, end - pos + 1));
return true;
}
/*! Parse a given SDP fmtp value string, returning the value of a specific integer option, if present.
*
* Example:
*
* const char *fmtp_vals = "octet-align=1;mode-set=0,2,4,7";
* bool oa = osmo_sdp_fmtp_get_int(fmtp_vals, OSMO_SDP_AMR_OCTET_ALIGN_NAME, 1);
*
* \param[in] fmtp fmtp value string to parse -- must not contain the "a=fmtp:N " prefix, only the value part.
* \param[in] option_name Which fmtp option to get the value for.
* \param[in] default_value If option_name is not present or cannot be parsed as integer, return this instead.
* \return the integer value when the option was found and actually an integer, default_value otherwise.
*/
int osmo_sdp_fmtp_get_int(const char *fmtp, const char *option_name, int default_value)
{
char val[128];
if (!osmo_sdp_fmtp_get_val(val, sizeof(val), fmtp, option_name))
return default_value;
if (!val[0])
return default_value;
int i;
if (osmo_str_to_int(&i, val, 10, 0, 1)) {
/* error parsing number */
LOGP(DLMGCP, LOGL_ERROR, "Invalid number in fmtp parameter '%s': '%s'\n", option_name, val);
return default_value;
}
return i;
}
/*! Return true if octet-align is present and set to 1 in the given AMR related fmtp value.
* Default to octet-align=0, i.e. bandwidth-efficient mode.
*
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
* Media Type Registration":
*
* octet-align: Permissible values are 0 and 1. If 1, octet-align
* operation SHALL be used. If 0 or if not present,
* bandwidth-efficient operation is employed.
*
* https://tools.ietf.org/html/rfc4867
*/
bool osmo_sdp_fmtp_amr_is_octet_aligned(const char *fmtp)
{
return osmo_sdp_fmtp_get_int(fmtp, OSMO_SDP_NAME_AMR_OCTET_ALIGN, 0) == 1;
}

View File

@@ -105,94 +105,6 @@ enum mgcp_codecs map_str_to_codec(const char *str)
return -1;
}
/* Check the ptmap for illegal mappings */
static int check_ptmap(const struct ptmap *ptmap)
{
/* Check if there are mappings that leave the IANA assigned dynamic
* payload type range. Under normal conditions such mappings should
* not occur */
/* Its ok to have a 1:1 mapping in the statically defined
* range, this won't hurt */
if (ptmap->codec == ptmap->pt)
return 0;
if (ptmap->codec < 96 || ptmap->codec > 127)
goto error;
if (ptmap->pt < 96 || ptmap->pt > 127)
goto error;
return 0;
error:
LOGP(DLMGCP, LOGL_ERROR,
"ptmap contains illegal mapping: codec=%u maps to pt=%u\n",
ptmap->codec, ptmap->pt);
return -1;
}
/*! Map a codec to a payload type.
* \ptmap[in] payload pointer to payload type map with specified payload types.
* \ptmap[in] ptmap_len length of the payload type map.
* \ptmap[in] codec the codec for which the payload type should be looked up.
* \returns assigned payload type */
unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
enum mgcp_codecs codec)
{
unsigned int i;
/*! Note: If the payload type map is empty or the codec is not found
* in the map, then a 1:1 mapping is performed. If the codec falls
* into the statically defined range or if the mapping table isself
* tries to map to the statically defined range, then the mapping
* is also ignored and a 1:1 mapping is performed instead. */
/* we may return the codec directly since enum mgcp_codecs directly
* corresponds to the statically assigned payload types */
if (codec < 96 || codec > 127)
return codec;
for (i = 0; i < ptmap_len; i++) {
/* Skip illegal map entries */
if (check_ptmap(ptmap) == 0 && ptmap->codec == codec)
return ptmap->pt;
ptmap++;
}
/* If nothing is found, do not perform any mapping */
return codec;
}
/*! Map a payload type to a codec.
* \ptmap[in] payload pointer to payload type map with specified payload types.
* \ptmap[in] ptmap_len length of the payload type map.
* \ptmap[in] payload type for which the codec should be looked up.
* \returns codec that corresponds to the specified payload type */
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
unsigned int pt)
{
unsigned int i;
/*! Note: If the payload type map is empty or the payload type is not
* found in the map, then a 1:1 mapping is performed. If the payload
* type falls into the statically defined range or if the mapping
* table isself tries to map to the statically defined range, then
* the mapping is also ignored and a 1:1 mapping is performed
* instead. */
/* See also note in map_codec_to_pt() */
if (pt < 96 || pt > 127)
return pt;
for (i = 0; i < ptmap_len; i++) {
if (check_ptmap(ptmap) == 0 && ptmap->pt == pt)
return ptmap->codec;
ptmap++;
}
/* If nothing is found, do not perform any mapping */
return pt;
}
static void _mgcp_client_conf_init(struct mgcp_client_conf *conf)
{
/* NULL and -1 default to MGCP_CLIENT_*_DEFAULT values */
@@ -388,11 +300,12 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
{
unsigned int pt;
unsigned int i;
char codec_resp[64];
char codec_resp[256];
int rc;
#define A_PTIME "a=ptime:"
#define A_RTPMAP "a=rtpmap:"
#define A_FMTP "a=fmtp:"
if (osmo_str_startswith(line, A_PTIME)) {
if (sscanf(line, A_PTIME "%u", &r->ptime) != 1) {
@@ -401,7 +314,7 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
return -EINVAL;
}
} else if (osmo_str_startswith(line, A_RTPMAP)) {
if (sscanf(line, A_RTPMAP "%d %63s", &pt, codec_resp) != 2) {
if (sscanf(line, A_RTPMAP "%d %255s", &pt, codec_resp) != 2) {
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
return -EINVAL;
@@ -440,6 +353,42 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
.codec = rc,
};
r->ptmap_len++;
} else if (osmo_str_startswith(line, A_FMTP)) {
if (sscanf(line, A_FMTP "%d %255s", &pt, codec_resp) != 2) {
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse SDP parameter, invalid fmtp: %s\n", osmo_quote_str(line, -1));
return -EINVAL;
}
/* Earlier, a line like "m=audio 16002 RTP/AVP 98 112 3" established the desired order of payloads, now
* enrich it with actual codec information provided by "a=rtpmap:..." entries.
* For each, find the entry with the right pt number and add the info there. */
for (i = 0; i < r->ptmap_len; i++) {
if (r->ptmap[i].pt != pt)
continue;
OSMO_STRLCPY_ARRAY(r->ptmap[r->ptmap_len].fmtp, codec_resp);
return 0;
}
/* No entry was found. This is an error in the MGCP protocol, but let's just add another entry
* anyway, to not make it look like it was never there. */
LOGP(DLMGCP, LOGL_ERROR,
"error in MGCP message: 'a=fmtp:%u' has no matching entry in 'm=audio ... %u'\n",
pt, pt);
if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
LOGP(DLMGCP, LOGL_ERROR,
"cannot parse all codecs: can only store up to %zu rtpmap entries.\n",
ARRAY_SIZE(r->ptmap));
return -ENOSPC;
}
r->ptmap[r->ptmap_len] = (struct ptmap){
.pt = pt,
.codec = -1,
};
OSMO_STRLCPY_ARRAY(r->ptmap[r->ptmap_len].fmtp, codec_resp);
r->ptmap_len++;
}
return 0;
@@ -728,7 +677,7 @@ static struct mgcp_response_pending *mgcp_client_response_pending_get(
/* Feed an MGCP message into the receive processing.
* Parse the head and call any callback registered for the transaction id found
* in the MGCP message. This is normally called directly from the internal
* mgcp_read_cb that reads from the socket connected to the MGCP gateway. This
* mgcp_do_read that reads from the socket connected to the MGCP gateway. This
* function is published mainly to be able to feed data from the test suite.
*/
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
@@ -781,58 +730,55 @@ error:
return rc;
}
static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
{
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
if (res <= 0) {
char errbuf[128] = "";
strerror_r(-res, errbuf, sizeof(errbuf));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
osmo_iofd_get_name(iofd), res, errbuf);
msgb_free(msg);
return;
}
msg->l2h = msg->head;
mgcp_client_rx(mgcp, msg);
talloc_free(msg);
}
static int mgcp_do_write(struct mgcp_client *mgcp, struct msgb *msg)
static int mgcp_do_read(struct osmo_fd *fd)
{
struct mgcp_client *mgcp = fd->data;
struct msgb *msg;
int ret;
msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
if (!msg) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed to allocate MGCP message.\n");
return -1;
}
/* msgb_tailroom() is basically (4096 - 128); -1 is for '\0' */
ret = read(fd->fd, msg->data, msgb_tailroom(msg) - 1);
if (ret <= 0) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
osmo_sock_get_name2(fd->fd), errno, strerror(errno));
msgb_free(msg);
return -1;
}
msg->l2h = msgb_put(msg, ret);
ret = mgcp_client_rx(mgcp, msg);
talloc_free(msg);
return ret;
}
static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
{
int ret;
struct mgcp_client *mgcp = fd->data;
LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
osmo_iofd_get_name(mgcp->iofd), msg->len,
osmo_sock_get_name2(fd->fd), msg->len,
osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
ret = osmo_iofd_write_msgb(mgcp->iofd, msg);
if (ret < 0)
msgb_free(msg);
ret = write(fd->fd, msg->data, msg->len);
if (OSMO_UNLIKELY(ret != msg->len))
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
osmo_sock_get_name2(fd->fd), errno, strerror(errno),
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
/* Re-arm the keepalive Tx timer: */
if (mgcp->actual.keepalive.req_interval_sec > 0)
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
return ret;
}
static void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
{
struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
if (OSMO_UNLIKELY(res != msg->len)) {
char errbuf[128] = "";
strerror_r(-res, errbuf, sizeof(errbuf));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
osmo_iofd_get_name(mgcp->iofd), res, errbuf,
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
}
}
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
{
static char endpoint[MGCP_ENDPOINT_MAXLEN];
@@ -864,10 +810,6 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
};
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
if (!msgb_dlcx) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname);
return;
}
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
}
@@ -881,10 +823,6 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
};
OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
if (!msgb_auep) {
LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname);
return;
}
mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
}
@@ -952,6 +890,11 @@ struct mgcp_client *mgcp_client_init(void *ctx,
if (conf->description)
mgcp->actual.description = talloc_strdup(mgcp, conf->description);
osmo_wqueue_init(&mgcp->wq, 1024);
mgcp->wq.read_cb = mgcp_do_read;
mgcp->wq.write_cb = mgcp_do_write;
osmo_fd_setup(&mgcp->wq.bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
memcpy(&mgcp->actual.keepalive, &conf->keepalive, sizeof(conf->keepalive));
osmo_timer_setup(&mgcp->keepalive_tx_timer, mgcp_client_keepalive_tx_timer_cb, mgcp);
osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
@@ -959,11 +902,6 @@ struct mgcp_client *mgcp_client_init(void *ctx,
return mgcp;
}
static const struct osmo_io_ops mgcp_clnt_ioops = {
.read_cb = mgcp_read_cb,
.write_cb = mgcp_write_cb,
};
/*! Initialize client connection (opens socket)
* \param[in,out] mgcp MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
@@ -979,28 +917,19 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
return -EINVAL;
}
rc = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
rc = osmo_sock_init2_ofd(&mgcp->wq.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rc < 0) {
LOGPMGW(mgcp, LOGL_FATAL,
"Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
strerror(errno));
goto error_free;
goto error_close_fd;
}
mgcp->iofd = osmo_iofd_setup(mgcp, rc, osmo_sock_get_name2(rc), OSMO_IO_FD_MODE_READ_WRITE,
&mgcp_clnt_ioops, mgcp);
if (!mgcp->iofd)
goto error_close_fd;
LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_iofd_get_name(mgcp->iofd));
osmo_iofd_register(mgcp->iofd, -1);
osmo_iofd_set_alloc_info(mgcp->iofd, 4096, 128);
osmo_iofd_set_txqueue_max_length(mgcp->iofd, 1024);
LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(mgcp->wq.bfd.fd));
/* If configured, send a DLCX message to the endpoints that are configured to
* be reset on startup. Usually this is a wildcarded endpoint. */
@@ -1026,10 +955,9 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
return 0;
error_close_fd:
close(rc);
error_free:
close(mgcp->wq.bfd.fd);
mgcp->wq.bfd.fd = -1;
return rc;
}
@@ -1046,6 +974,8 @@ int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
* \returns 0 on success, -EINVAL on error. */
void mgcp_client_disconnect(struct mgcp_client *mgcp)
{
struct osmo_wqueue *wq;
if (!mgcp) {
LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
return;
@@ -1056,10 +986,13 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
osmo_timer_del(&mgcp->keepalive_tx_timer);
mgcp->conn_up = false;
osmo_iofd_txqueue_clear(mgcp->iofd);
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd));
osmo_iofd_free(mgcp->iofd);
mgcp->iofd = NULL;
wq = &mgcp->wq;
osmo_wqueue_clear(wq);
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
if (osmo_fd_is_registered(&wq->bfd))
osmo_fd_unregister(&wq->bfd);
close(wq->bfd.fd);
wq->bfd.fd = -1;
}
/*! Get the IP-Aaddress of the associated MGW as string.
@@ -1213,9 +1146,10 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
goto mgcp_tx_error;
}
rc = mgcp_do_write(mgcp, msg);
rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
if (rc) {
LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
msgb_free(msg);
goto mgcp_tx_error;
} else
LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
@@ -1320,36 +1254,6 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
#undef MSGB_PRINTF_OR_RET
}
/* Helper function to obtain local IP address used in MGCP towards MGW,
* in string format, to fill the SDP "Origin" ("o=") field.
* return 0 on success, negative on error.
*/
static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len)
{
int fd;
/* Try to get the socket local IP address if available: */
if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) {
if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0)
return 0;
/* else: continue below */
}
/* If MGCP local address was explicitly specified in config, use it: */
if (mgcp->actual.local_addr) {
osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len);
return 0;
}
/* Guess our local address based on system routing towards MGW: */
OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN);
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0)
return 0;
LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n");
return -EINVAL;
}
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
{
@@ -1358,8 +1262,6 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
int local_ip_family, audio_ip_family;
const char *codec;
unsigned int pt;
uint16_t audio_port;
int rc;
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
@@ -1375,9 +1277,11 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
MSGB_PRINTF_OR_RET("v=0\r\n");
/* Determine local IP-Address */
rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip));
if (rc < 0)
return rc;
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
LOGPMGW(mgcp, LOGL_ERROR,
"Could not determine local IP-Address!\n");
return -EINVAL;
}
local_ip_family = osmo_ip_str_type(local_ip);
if (local_ip_family == AF_UNSPEC)
return -EINVAL;
@@ -1409,28 +1313,33 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
MSGB_PRINTF_OR_RET("t=0 0\r\n");
/* Add RTP address port and codecs */
audio_port = 0;
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)) {
audio_port = mgcp_msg->audio_port;
if (!audio_port) {
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT) {
if (mgcp_msg->audio_port == 0) {
LOGPMGW(mgcp, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
return -EINVAL;
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
for (i = 0; i < mgcp_msg->ptmap_len; i++)
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
MSGB_PRINTF_OR_RET("\r\n");
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", audio_port);
for (i = 0; i < mgcp_msg->ptmap_len; i++)
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
MSGB_PRINTF_OR_RET("\r\n");
/* Add optional codec parameters (fmtp) */
if (mgcp_msg->param_present) {
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
/* The following is only applicable for AMR */
if (mgcp_msg->ptmap[i].codec != CODEC_AMR_8000_1
&& mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1)
continue;
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
/* Add fmtp string, if any is set. */
if (mgcp_msg->ptmap[i].fmtp[0]) {
MSGB_PRINTF_OR_RET("a=fmtp:%u %s\r\n", mgcp_msg->ptmap[i].pt, mgcp_msg->ptmap[i].fmtp);
continue;
}
/* LEGACY COMPAT. Fill in fmtp with the legacy mgcp_msg->param, if any, when no individual fmtp is set
* on the codec. We only ever supported AMR fmtp in mgcp_msg->param. */
if (mgcp_msg->param_present
&& (mgcp_msg->ptmap[i].codec == CODEC_AMR_8000_1
|| mgcp_msg->ptmap[i].codec == CODEC_AMRWB_16000_1)) {
pt = mgcp_msg->ptmap[i].pt;
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt);
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
@@ -1668,5 +1577,8 @@ int ptmap_cmp(const struct ptmap *a, const struct ptmap *b)
rc = OSMO_CMP(a->codec, b->codec);
if (rc)
return rc;
return OSMO_CMP(a->pt, b->pt);
rc = OSMO_CMP(a->pt, b->pt);
if (rc)
return rc;
return strcmp(a->fmtp, b->fmtp);
}

View File

@@ -157,7 +157,6 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
mgcp_msg->conn_mode = conn_mode;
}
/* returns message buffer containing MGXP MDCX on success, NULL on error. */
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
{
struct mgcp_msg mgcp_msg;
@@ -193,7 +192,6 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
}
/* returns message buffer containing MGXP DLCX on success, NULL on error. */
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
{
struct mgcp_msg mgcp_msg;
@@ -233,10 +231,8 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
if (!msg) {
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
return;
}
OSMO_ASSERT(msg);
mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
mgcp_ctx->mgw_trans_pending = true;
rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
@@ -628,6 +624,17 @@ static struct osmo_fsm fsm_mgcp_client = {
.log_subsys = DLMGCP,
};
/*! allocate struct to hold the description of an MGCP connection peer.
* \param[in] ctx talloc context.
* \returns newly-allocated and initialized struct mgcp_conn_peer. */
struct mgcp_conn_peer *mgcp_conn_peer_alloc(void *ctx)
{
struct mgcp_conn_peer *peer;
peer = talloc_zero(ctx, struct mgcp_conn_peer);
OSMO_ASSERT(peer);
return peer;
}
/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
* that has codecs[] set, apply it to ptmap[] instead. */
static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)

View File

@@ -322,7 +322,7 @@ DEFUN(cfg_mgw_mgw_keepalive_req_interval,
/* If client already exists, apply the change immediately if possible: */
mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
if (mgcp->iofd) { /* UDP MGCP socket connected */
if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
if (mgcp->actual.keepalive.req_interval_sec > 0) {
/* Re-schedule: */
osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
@@ -375,7 +375,7 @@ DEFUN(cfg_mgw_mgw_keepalive_timeout,
/* If client already exists, apply the change immediately if possible: */
mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
if (mgcp->iofd) { /* UDP MGCP socket connected */
if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
if (mgcp->actual.keepalive.timeout_sec > 0) {
/* Re-schedule: */
osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
@@ -680,7 +680,7 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
const struct mgcp_client *cli = pool_member->client;
vty_out(vty, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
vty_out(vty, "%% MGCP link: %s,%s%s",
cli && cli->iofd ? "connected" : "disconnected",
cli && cli->wq.bfd.fd != -1 ? "connected" : "disconnected",
cli && cli->conn_up ?
((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
"DOWN",

View File

@@ -40,7 +40,7 @@ libosmo_mgcp_a_SOURCES = \
mgcp_endp.c \
mgcp_trunk.c \
mgcp_ratectr.c \
mgcp_rtp_end.c \
mgcp_e1.c \
mgcp_iuup.c \
$(top_srcdir)/src/libosmo-mgcp-client/fmtp.c \
$(NULL)

View File

@@ -24,11 +24,12 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp_client/fmtp.h>
#include <errno.h>
/* Helper function to dump codec information of a specified codec to a printable
* string, used by dump_codec_summary() */
static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
static char *dump_codec(struct mgcp_rtp_codec *codec)
{
static char str[256];
char *pt_str;
@@ -49,25 +50,31 @@ static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
}
/*! Dump a summary of all negotiated codecs to debug log
* \param[in] cset related codecset.
* \param[in] prefix_str Prefix string to print during logging.
* */
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
* \param[in] conn related rtp-connection. */
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_end *rtp;
unsigned int i;
struct mgcp_rtp_codec *codec;
struct mgcp_endpoint *endp;
if (cset->codecs_assigned == 0) {
LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
rtp = &conn->end;
endp = conn->conn->endp;
if (rtp->codecs_assigned == 0) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
mgcp_conn_dump(conn->conn));
return;
}
/* Store parsed codec information */
for (i = 0; i < cset->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec = &cset->codecs[i];
for (i = 0; i < rtp->codecs_assigned; i++) {
codec = &rtp->codecs[i];
LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
if (codec == cset->codec)
if (codec == rtp->codec)
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
LOGPC(DLMGCP, LOGL_DEBUG, "\n");
@@ -75,7 +82,7 @@ void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_st
}
/* Initalize or reset codec information with default data. */
static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
static void codec_init(struct mgcp_rtp_codec *codec)
{
*codec = (struct mgcp_rtp_codec){
.payload_type = -1,
@@ -88,20 +95,20 @@ static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
};
}
static void mgcp_codec_free(struct mgcp_rtp_codec *codec)
static void codec_free(struct mgcp_rtp_codec *codec)
{
*codec = (struct mgcp_rtp_codec){};
}
/*! Initalize or reset codec information with default data.
* \param[out] conn related rtp-connection. */
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
{
int i;
for (i = 0; i < cset->codecs_assigned; i++)
mgcp_codec_free(&cset->codecs[i]);
cset->codecs_assigned = 0;
cset->codec = NULL;
for (i = 0; i < conn->end.codecs_assigned; i++)
codec_free(&conn->end.codecs[i]);
conn->end.codecs_assigned = 0;
conn->end.codec = NULL;
}
/*! Add codec configuration depending on payload type and/or codec name. This
@@ -110,25 +117,25 @@ void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
* \param[out] conn related rtp-connection.
* \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
* \param[in] param optional codec parameters (set to NULL when unused).
* \param[in] fmtp optional codec parameters (set to NULL when unused).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
int mgcp_codec_add2(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const char *fmtp)
{
int rate;
int channels;
struct mgcp_rtp_codec *codec;
unsigned int pt_offset = cset->codecs_assigned;
unsigned int pt_offset = conn->end.codecs_assigned;
/* The amount of codecs we can store is limited, make sure we do not
* overrun this limit. */
if (cset->codecs_assigned >= MGCP_MAX_CODECS)
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
return -EINVAL;
/* First unused entry */
codec = &cset->codecs[cset->codecs_assigned];
codec = &conn->end.codecs[conn->end.codecs_assigned];
/* Initalize the codec struct with some default data to begin with */
mgcp_codec_init(codec);
codec_init(codec);
if (payload_type != PTYPE_UNDEFINED) {
/* Make sure we do not get any reserved or undefined type numbers */
@@ -255,42 +262,56 @@ int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, co
}
}
/* Copy over optional codec parameters */
if (param) {
codec->param = *param;
codec->param_present = true;
} else
codec->param_present = false;
if (fmtp) {
OSMO_STRLCPY_ARRAY(codec->fmtp, fmtp);
if (strlen(codec->fmtp) != strlen(fmtp)) {
LOGP(DLMGCP, LOGL_ERROR, "fmtp too long: %zu > %zu\n", strlen(fmtp), strlen(codec->fmtp));
/* let's just hope what is there is still useful, worst case the call's audio doesn't work */
}
}
cset->codecs_assigned++;
/* legacy */
codec->param_present = false;
conn->end.codecs_assigned++;
return 0;
error:
/* Make sure we leave a clean codec entry on error. */
mgcp_codec_free(codec);
codec_free(codec);
return -EINVAL;
}
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
* Media Type Registration":
*
* octet-align: Permissible values are 0 and 1. If 1, octet-aligned
* operation SHALL be used. If 0 or if not present,
* bandwidth-efficient operation is employed.
*
* https://tools.ietf.org/html/rfc4867
*/
/*! Legacy compat, use mgcp_codec_add2() instead to be able to pass any fmtp besides AMR octet-align=1.
* Add codec configuration depending on payload type and/or codec name. This
* function uses the input parameters to extrapolate the full codec information.
* \param[out] codec configuration (caller provided memory).
* \param[out] conn related rtp-connection.
* \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
* \param[in] param optional codec parameters (set to NULL when unused).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
{
const char *fmtp = NULL;
if (param && param->amr_octet_aligned_present)
fmtp = OSMO_SDP_AMR_SET_OCTET_ALIGN(param->amr_octet_aligned);
return mgcp_codec_add2(conn, payload_type, audio_name, fmtp);
}
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
{
if (!codec->param_present)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
return codec->param.amr_octet_aligned;
/* Legacy */
if (!codec->fmtp[0]
&& codec->param_present
&& codec->param.amr_octet_aligned_present)
return codec->param.amr_octet_aligned;
return osmo_sdp_fmtp_amr_is_octet_aligned(codec->fmtp);
}
/* Compare two codecs, all parameters must match up */
static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
* exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
@@ -319,7 +340,7 @@ static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_
}
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
{
/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
* translate between different payload formats as long as the encoded voice data itself does not change.
@@ -348,18 +369,21 @@ iufp:
return true;
}
struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int codecs_assigned;
rtp_end = &conn->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codecs_assigned = cset->codecs_assigned;
codecs_assigned = rtp_end->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_same(codec, &cset->codecs[i])) {
return &cset->codecs[i];
if (codecs_same(codec, &rtp_end->codecs[i])) {
return &rtp_end->codecs[i];
break;
}
}
@@ -368,26 +392,28 @@ struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, c
}
/* For a given codec, find a convertible codec in the given connection. */
static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int codecs_assigned;
struct mgcp_rtp_codec *codec_convertible = NULL;
rtp_end = &conn->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codec_convertible = mgcp_codecset_find_same(cset, codec);
codec_convertible = mgcp_codec_find_same(conn, codec);
if (codec_convertible)
return codec_convertible;
/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
* payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
codecs_assigned = cset->codecs_assigned;
codecs_assigned = rtp_end->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_convertible(codec, &cset->codecs[i])) {
codec_convertible = &cset->codecs[i];
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
codec_convertible = &rtp_end->codecs[i];
break;
}
}
@@ -397,20 +423,40 @@ static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
* a tentative decision is made.
* \param[in] cset_src related codec set.
* \param[inout] cset_dst related destination codec set (NULL if not present).
* \param[inout] conn_src related rtp-connection.
* \param[inout] conn_dst related destination rtp-connection (NULL if not present).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
{
unsigned int i;
if (log_check_level(DLMGCP, LOGL_DEBUG)) {
LOGP(DLMGCP, LOGL_DEBUG, "%s(): src.codecs_assigned=%d dst.codecs_assigned=%d\n",
__func__,
conn_src ? conn_src->end.codecs_assigned : 0,
conn_dst ? conn_dst->end.codecs_assigned : 0);
if (conn_src) {
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *c = &conn_src->end.codecs[i];
LOGP(DLMGCP, LOGL_DEBUG, "src.codecs[%d]: %d %s %s %s\n",
i, c->payload_type, c->audio_name, c->subtype_name, c->fmtp);
}
}
if (conn_dst) {
for (i = 0; i < conn_dst->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *c = &conn_dst->end.codecs[i];
LOGP(DLMGCP, LOGL_DEBUG, "dst.codecs[%d]: %d %s %s %s\n",
i, c->payload_type, c->audio_name, c->subtype_name, c->fmtp);
}
}
}
/* In case no destination connection is available (yet), or in case the destination connection exists but has
* no codecs assigned, we are forced to make a simple tentative decision:
* We just use the first codec of the source connection (conn_src) */
OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
if (!cset_dst || cset_dst->codecs_assigned == 0) {
if (cset_src->codecs_assigned >= 1) {
cset_src->codec = &cset_src->codecs[0];
OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
if (conn_src->end.codecs_assigned >= 1) {
conn_src->end.codec = &conn_src->end.codecs[0];
return 0;
} else
return -EINVAL;
@@ -419,38 +465,39 @@ int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_cod
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
* of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
* required. */
for (i = 0; i < cset_src->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
if (codec_cset_dst) {
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src);
if (codec_conn_dst) {
/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
* sides. We now set this codec on both connections. */
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
return 0;
}
}
/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
* to convert. */
for (i = 0; i < cset_src->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
if (codec_cset_dst) {
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src);
if (codec_conn_dst) {
/* We found the a codec that we can convert to. Set each side to its codec. */
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
return 0;
}
}
if (cset_dst->codecs_assigned)
cset_dst->codec = &cset_dst->codecs[0];
LOGP(DLMGCP, LOGL_ERROR, "no matching codec found\n");
if (conn_dst->end.codecs_assigned)
conn_dst->end.codec = &conn_dst->end.codecs[0];
else
return -EINVAL;
if (cset_src->codecs_assigned)
cset_src->codec = &cset_src->codecs[0];
if (conn_src->end.codecs_assigned)
conn_src->end.codec = &conn_src->end.codecs[0];
else
return -EINVAL;
@@ -460,13 +507,13 @@ int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_cod
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
{
if (codec->param_present == false)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
if (strcmp(codec->subtype_name, "AMR") != 0)
return false;
return true;
if (!codec->fmtp[0]) {
/* Legacy */
return codec->param_present && codec->param.amr_octet_aligned_present;
}
/* Just check for presence, not the actual value. */
return osmo_sdp_fmtp_get_val(NULL, 0, codec->fmtp, OSMO_SDP_NAME_AMR_OCTET_ALIGN);
}
/* Find the payload type number configured for a specific codec by SDP.
@@ -477,36 +524,38 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
* with incrementing match_nr.
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr)
{
int i;
for (i = 0; i < cset->codecs_assigned; i++) {
if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
for (i = 0; i < conn->end.codecs_assigned; i++) {
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
if (match_nr) {
match_nr--;
continue;
}
return &cset->codecs[i];
return &conn->end.codecs[i];
}
}
return NULL;
}
/*! Lookup a codec that is assigned to a connection by its payload type number.
* \param[in] cset related codec set.
* \param[in] conn related rtp-connection.
* \param[in] payload_type number of the codec to look up.
* \returns pointer to codec struct on success, NULL on failure. */
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
{
struct mgcp_rtp_end *rtp_end = &conn->end;
unsigned int codecs_assigned = rtp_end->codecs_assigned;
struct mgcp_rtp_codec *codec = NULL;
size_t i;
OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < cset->codecs_assigned; i++) {
if (payload_type == cset->codecs[i].payload_type) {
codec = &cset->codecs[i];
for (i = 0; i < codecs_assigned; i++) {
if (payload_type == rtp_end->codecs[i].payload_type) {
codec = &rtp_end->codecs[i];
break;
}
}

View File

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

View File

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

View File

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

View File

@@ -264,7 +264,6 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
uint8_t *amr_data;
struct rtp_hdr *rtp_hdr;
struct amr_hdr *amr_hdr;
struct mgcp_rtp_codec *dst_codec;
int rc;
ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
@@ -276,8 +275,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
}
msgb_pull_to_l3(msg);
dst_codec = conn_rtp_dst->end.cset.codec;
if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
amr_hdr->cmr = 15; /* no change */
@@ -305,7 +303,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
.extension = 0,
.padding = 0,
.version = 0,
.payload_type = dst_codec->payload_type,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = frame_nr,
.timestamp = 0,
@@ -313,6 +311,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
};
rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
msgb_free(msg);
return rc;
}
@@ -470,7 +469,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
int buflen = msgb_length(msg);
char *dest_name;
int rc;
int len;
OSMO_ASSERT(conn_src);
OSMO_ASSERT(conn_dst);
@@ -504,10 +503,9 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
* ignored by the receiver, but still it's useful for debug purposes
* to set it. Moreover, it seems ip.access nano3g produces much worse
* audio output on the air side if timestamp is not set properly. */
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
rtp_state->alt_rtp_tx_sequence++;
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
@@ -515,17 +513,19 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
if (rc < 0)
return rc;
if (len <= 0)
return len;
rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
return len;
}
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
@@ -546,13 +546,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
msgb_pull_to_l2(msg);
rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
/* rtph is further filled in mgcp_send_iuup() below. */
/* TODO: fill rtph properly: */
*rtph = (struct rtp_hdr){
.csrc_count = 0,
.extension = 0,
.padding = 0,
.version = 2,
.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.marker = 0,
.sequence = 0,
.timestamp = 0,
@@ -640,14 +640,13 @@ free_ret:
}
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
* peer and send it down the IuUP layer towards the destination as IuUP/RTP. Takes ownership of msg. */
* peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
{
struct osmo_iuup_rnl_prim *irp;
struct rtp_hdr *rtph;
int rc = -1;
int iuup_length = 0;
struct mgcp_rtp_codec *src_codec;
int8_t rfci;
/* Tx RNL-DATA.req */
@@ -660,14 +659,13 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
/* TODO: CMR handling & multiple frames handling */
src_codec = conn_src_rtp->end.cset.codec;
if (strcmp(src_codec->subtype_name, "AMR") != 0) {
if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
"Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
src_codec->subtype_name);
conn_src_rtp->end.codec->subtype_name);
goto free_ret;
}
if (mgcp_codec_amr_is_octet_aligned(src_codec)) {
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
if (msgb_length(msg) < (sizeof(*amr_hdr))) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,

View File

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

View File

@@ -4,7 +4,6 @@
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -71,20 +70,14 @@ 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)
{
return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
(osmo_sockaddr_is_any(&rtp_end->addr) == 0);
}
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address.
* \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
@@ -332,7 +325,7 @@ static int adjust_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
osmo_sockaddr_port(&addr->u.sa));
} else {
tsdelta = rtp_end->cset.codec->rate * 20 / 1000;
tsdelta = rtp_end->codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"Fixed packet duration and last timestamp delta "
"are not available, "
@@ -411,12 +404,15 @@ static int align_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
* \param[in] associated endpoint.
* \param[in] destination RTP end.
* \param[in,out] msg message bufffer containing data. Function might change length.
* \param[in,out] pointer to buffer with voice data.
* \param[in] voice data length.
* \param[in] maximum size of caller provided voice data buffer.
* \returns ignores input parameters, return always 0. */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct msgb *msg)
char *data, int *len, int buf_size)
{
LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
return 0;
}
@@ -496,11 +492,11 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
}
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
if (!conn_dst->end.cset.codec) {
if (!conn_dst->end.codec) {
LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
return -EINVAL;
}
rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type;
rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
return 0;
}
@@ -523,8 +519,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
uint32_t timestamp, ssrc;
bool marker_bit;
struct rtp_hdr *rtp_hdr;
struct mgcp_rtp_codec *codec = rtp_end->cset.codec;
int payload = codec->payload_type;
int payload = rtp_end->codec->payload_type;
unsigned int len = msgb_length(msg);
if (len < sizeof(*rtp_hdr))
@@ -533,7 +528,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
seq = ntohs(rtp_hdr->sequence);
timestamp = ntohl(rtp_hdr->timestamp);
arrival_time = mgcp_get_current_ts(codec->rate);
arrival_time = mgcp_get_current_ts(rtp_end->codec->rate);
ssrc = ntohl(rtp_hdr->ssrc);
marker_bit = !!rtp_hdr->marker;
transit = arrival_time - timestamp;
@@ -542,16 +537,16 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
if (!state->initialized) {
state->initialized = 1;
state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end);
state->in_stream.last_seq = seq - 1;
state->in_stream.ssrc = ssrc;
state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
state->in_stream.last_tsdelta = 0;
state->packet_duration =
mgcp_rtp_packet_duration(endp, rtp_end);
state->out_stream.last_seq = seq - 1;
state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
state->out_stream.last_tsdelta = 0;
state->out_stream.last_timestamp = timestamp;
state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
state->patch.orig_ssrc = ssrc;
state->patch.patch_ssrc = rtp_end->force_constant_ssrc;
LOGPENDP(endp, DRTP, LOGL_INFO,
"initializing stream, SSRC: %u timestamp: %u "
"pkt-duration: %d, from %s:%d\n",
@@ -561,7 +556,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
osmo_sockaddr_port(&addr->u.sa));
if (state->packet_duration == 0) {
state->packet_duration =
codec->rate * 20 / 1000;
rtp_end->codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"fixed packet duration is not available, "
"using fixed 20ms instead: %d from %s:%d\n",
@@ -578,7 +573,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
osmo_sockaddr_port(&addr->u.sa));
state->in_stream.ssrc = ssrc;
if (state->patch.patch_ssrc) {
if (rtp_end->force_constant_ssrc) {
int16_t delta_seq;
/* Always increment seqno by 1 */
@@ -594,7 +589,10 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
delta_seq, timestamp, marker_bit);
state->patch.patch_ssrc = true;
ssrc = state->patch.orig_ssrc;
if (rtp_end->force_constant_ssrc != -1)
rtp_end->force_constant_ssrc -= 1;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"SSRC patching enabled, SSRC: %u "
@@ -787,18 +785,16 @@ static int amr_oa_check(char *data, int len)
/* Forward data to a debug tap. This is debug function that is intended for
* debugging the voice traffic with tools like gstreamer */
void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg)
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
{
int rc;
if (!tap->enabled)
return;
struct msgb *msg2 = msgb_copy(msg, "RTP TAP Tx");
if (!msg2)
return;
rc = sendto(fd, msgb_data(msg), msgb_length(msg), 0, (struct sockaddr *)&tap->forward,
sizeof(tap->forward));
rc = osmo_iofd_sendto_msgb(iofd, msg2, 0, &tap->forward);
if (rc < 0)
LOGP(DRTP, LOGL_ERROR,
"Forwarding tapped (debug) voice data failed.\n");
@@ -814,8 +810,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
return;
hdr->version = 2;
hdr->payload_type = rtp_end->cset.codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
hdr->payload_type = rtp_end->codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
hdr->ssrc = state->alt_rtp_tx_ssrc;
}
@@ -970,7 +966,7 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
return 0;
}
/*! Dispatch msg bridged from the sister conn in the endpoint. Takes ownership of msgb.
/*! Dispatch msg bridged from the sister conn in the endpoint.
* \param[in] conn_dst The destination conn that should handle and transmit the content to
* its peer outside MGW.
* \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
@@ -992,10 +988,8 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
/* Before we try to deliver the packet, we check if the destination
* port and IP-Address make sense at all. If not, we will be unable
* to deliver the packet. */
if (check_rtp_destin(conn_dst) != 0) {
msgb_free(msg);
if (check_rtp_destin(conn_dst) != 0)
return -1;
}
/* Depending on the RTP connection type, deliver the RTP packet to the
* destination connection. */
@@ -1030,46 +1024,39 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
* be discarded, this should not happen, normally the MGCP type
* should be properly set */
LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
msgb_free(msg);
return -1;
}
/*! send message buffer via udp socket. If it succeeds, it takes ownership of the msgb and internally calls
* msgb_free() after the aynchronous sendto() completes. In case of error, the msgb is still owned by the
* caller and must be free'd accordingly.
* \param[in] iofd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] msg message buffer that holds the data to be send.
* \returns 0 in case of success (takes msgb ownership), -1 on error (doesn't take msgb ownership). */
static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, struct msgb *msg)
{
LOGP(DRTP, LOGL_DEBUG, "sending %d bytes length packet to %s ...\n", msgb_length(msg),
osmo_sockaddr_to_str(addr));
return osmo_iofd_sendto_msgb(iofd, msg, 0, addr);
}
/*! send udp packet from raw buffer/length.
* \param[in] iofd associated file descriptor.
/*! send udp packet.
* \param[in] fd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] buf buffer that holds the data to be send.
* \param[in] len length of the data to be sent.
* \returns 0 in case of success, -1 on error. */
int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len)
* \returns bytes sent, -1 on error. */
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
{
struct msgb *msg = msgb_alloc_c(iofd, len, "mgcp_udp_send");
if (!msg)
return -ENOMEM;
memcpy(msg->tail, buf, len);
msgb_put(msg, len);
char ipbuf[INET6_ADDRSTRLEN];
size_t addr_len;
return mgcp_udp_send_msg(iofd, addr, msg);
LOGP(DRTP, LOGL_DEBUG,
"sending %i bytes length packet to %s:%u ...\n", len,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
osmo_sockaddr_port(&addr->u.sa));
if (addr->u.sa.sa_family == AF_INET6) {
addr_len = sizeof(addr->u.sin6);
} else {
addr_len = sizeof(addr->u.sin);
}
return sendto(fd, buf, len, 0, &addr->u.sa, addr_len);
}
/*! send RTP dummy packet (to keep NAT connection open).
* \param[in] endp mcgp endpoint that holds the RTP connection.
* \param[in] conn associated RTP connection.
* \returns 0 in case of success, -1 on error. */
* \returns bytes sent, -1 on error. */
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int rc;
@@ -1091,7 +1078,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
if (mgcp_conn_rtp_is_iuup(conn))
rc = mgcp_conn_iuup_send_dummy(conn);
else
rc = mgcp_udp_send(conn->end.rtp, &conn->end.addr, rtp_dummy_payload, sizeof(rtp_dummy_payload));
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
goto failed;
@@ -1102,10 +1090,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
was_rtcp = 1;
rtcp_addr = conn->end.addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
rc = mgcp_udp_send(conn->end.rtcp, &rtcp_addr,
rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == 0)
if (rc >= 0)
return rc;
failed:
@@ -1116,7 +1104,7 @@ failed:
return -1;
}
/*! Send RTP/RTCP data to a specified destination connection. Takes ownership of msg.
/*! Send RTP/RTCP data to a specified destination connection.
* \param[in] endp associated endpoint (for configuration, logging).
* \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
* \param[in] addr spoofed source address (set to NULL to disable).
@@ -1155,7 +1143,6 @@ 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;
}
}
@@ -1181,73 +1168,73 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
struct mgcp_rtp_codec *src_codec;
struct mgcp_rtp_codec *dst_codec;
int cont;
int nbytes = 0;
int buflen = msgb_length(msg);
/* Make sure we have a valid RTP header, in cases where no RTP
* header is present, we will generate one. */
gen_rtp_header(msg, rtp_end, rtp_state);
/* Run transcoder */
rc = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error %d during transcoding\n", rc);
msgb_free(msg);
return rc;
}
do {
/* Run transcoder */
cont = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, (char *)msgb_data(msg), &buflen, RTP_BUF_SIZE);
if (cont < 0)
break;
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, msg);
src_codec = conn_src->end.cset.codec;
dst_codec = conn_dst->end.cset.codec;
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(dst_codec)) {
rc = amr_oa_bwe_convert(endp, msg, dst_codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
msgb_free(msg);
return rc;
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
bool oa = mgcp_codec_amr_is_octet_aligned(conn_dst->end.codec);
rc = amr_oa_bwe_convert(endp, msg, oa);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
oa ? "octet-aligned" : "bandwidth-efficient");
break;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
break;
}
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(src_codec->subtype_name, "GSM-HR-08") == 0) {
rc = rfc5993_hr_convert(endp, msg);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
msgb_free(msg);
return rc;
}
}
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
len = msgb_length(msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
(char *)msgb_data(msg), msgb_length(msg));
rc = mgcp_udp_send_msg(rtp_end->rtp, &rtp_end->addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
if (len <= 0)
return len;
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
nbytes += len;
buflen = cont;
} while (buflen > 0);
return nbytes;
} else if (!trunk->omit_rtcp) {
struct osmo_sockaddr rtcp_addr = rtp_end->addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(rtp_end->rtcp_port));
osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"send to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
@@ -1255,54 +1242,19 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtcp_addr.u.sa)
);
len = msgb_length(msg);
rc = mgcp_udp_send_msg(rtp_end->rtcp, &rtcp_addr, msg);
if (rc < 0) {
msgb_free(msg);
return rc;
}
len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
(char *)msgb_data(msg), msgb_length(msg));
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
rtp_state->alt_rtp_tx_sequence++;
return 0;
return len;
}
msgb_free(msg);
return 0;
}
/*! determine if there's only a single recipient in endp for data received via conn_src.
* The function returns NULL in case there is no recipient, or in case there are multiple recipients.
* \param endp The MGCP endpoint whose connections to analyze
* \param conn_src The source MGCP connection [which shall not count in results]
* \returns recipient donnection if there is only one; NULL in case there are multiple */
static struct mgcp_conn *rtpbridge_get_only_recipient(struct mgcp_endpoint *endp, struct mgcp_conn *conn_src)
{
struct mgcp_conn *conn_ret = NULL;
struct mgcp_conn *conn_dst;
llist_for_each_entry(conn_dst, &endp->conns, entry) {
if (conn_dst == conn_src)
continue;
switch (conn_dst->mode) {
case MGCP_CONN_SEND_ONLY:
case MGCP_CONN_RECV_SEND:
case MGCP_CONN_CONFECHO:
if (conn_ret)
return NULL;
conn_ret = conn_dst;
break;
default:
break;
}
}
return conn_ret;
}
/*! Dispatch incoming RTP packet to opposite RTP connection.
* \param[in] msg Message buffer to bridge, coming from source connection.
* msg shall contain "struct osmo_rtp_msg_ctx *" attached in
@@ -1339,13 +1291,13 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
memcpy(&conn_src->end.addr, from_addr,
sizeof(conn_src->end.addr));
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
osmo_sockaddr_port(&conn_src->end.addr.u.sa));
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
@@ -1360,44 +1312,23 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
return rc;
}
/* All the use cases above are 1:1 where we have one source msgb and we're sending that to one
* destination. msgb ownership had been passed to the respective _*dospatch_rtp() function.
* In the cases below, we actually [can] have multiple recipients, so we copy the original msgb
* for each of the recipients. */
/* If the mode is "confecho", send RTP back to the sender. */
if (conn->mode == MGCP_CONN_CONFECHO) {
struct msgb *msg2 = mgw_msgb_copy_c(conn, msg, "RTP confecho");
if (OSMO_LIKELY(msg2))
rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg2);
}
if (conn->mode == MGCP_CONN_CONFECHO)
rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
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;
}
/* 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;
}
/* as we only sent copies in the previous llist_for_each_entry() loop, we must free the
* original one */
msgb_free(msg);
}
return rc;
}
@@ -1424,19 +1355,19 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
memcpy(&conn_src->end.addr, from_addr,
sizeof(conn_src->end.addr));
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
osmo_sockaddr_port(&conn_src->end.addr.u.sa));
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
/* Forward to E1 */
return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg);
return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
}
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1469,7 +1400,7 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
}
/* Handle incoming RTP data from NET */
static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *saddr)
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
{
/* NOTE: This is a generic implementation. RTP data is received. In
* case of loopback the data is just sent back to its origin. All
@@ -1480,34 +1411,49 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
struct mgcp_conn_rtp *conn_src;
struct mgcp_endpoint *endp;
struct osmo_sockaddr addr;
socklen_t slen = sizeof(addr);
char ipbuf[INET6_ADDRSTRLEN];
int ret;
enum rtp_proto proto;
struct osmo_rtp_msg_ctx *mc;
struct msgb *msg;
int rc;
conn_src = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
conn_src = (struct mgcp_conn_rtp *)fd->data;
OSMO_ASSERT(conn_src);
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx");
proto = (iofd == conn_src->end.rtp) ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
if (res <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(-res));
goto out_free;
ret = recvfrom(fd->fd, msgb_data(msg), msg->data_len, 0, (struct sockaddr *)&addr.u.sa, &slen);
if (ret <= 0) {
LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
rc = -1;
goto out;
}
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s\n",
msgb_put(msg, ret);
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
msgb_length(msg), osmo_sockaddr_to_str(saddr));
msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
osmo_sockaddr_port(&addr.u.sa));
if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
|| (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
/* Logging happened in the two check_ functions */
goto out_free;
rc = -1;
goto out;
}
if (mgcp_is_rtp_dummy_payload(msg)) {
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
goto out_free;
rc = 0;
goto out;
}
/* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
@@ -1516,7 +1462,7 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
*mc = (struct osmo_rtp_msg_ctx){
.proto = proto,
.conn_src = conn_src,
.from_addr = (struct osmo_sockaddr *) saddr,
.from_addr = &addr,
};
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
mc->proto, mc->conn_src,
@@ -1531,17 +1477,16 @@ static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(iofd, &conn_src->tap_in, msg);
forward_data_tap(fd->fd, &conn_src->tap_in, msg);
rx_rtp(msg);
return;
rc = rx_rtp(msg);
out_free:
out:
msgb_free(msg);
return rc;
}
/* Note: This function is able to handle RTP and RTCP. msgb ownership is transferred, so this function or its
* downstream consumers must make sure to [eventually] free the msgb. */
/* Note: This function is able to handle RTP and RTCP */
static int rx_rtp(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
@@ -1554,23 +1499,25 @@ static int rx_rtp(struct msgb *msg)
/* Check if the origin of the RTP packet seems plausible */
if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
goto out_free;
return -1;
/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
if (mc->proto == MGCP_PROTO_RTP
&& conn_src->end.cset.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) {
&& conn_src->end.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
bool src_oa;
/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
* communicated via SDP when the connection was created/modfied. */
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
goto out_free;
if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) {
return -1;
src_oa = mgcp_codec_amr_is_octet_aligned(conn_src->end.codec);
if (((bool)oa) != src_oa) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa);
goto out_free;
msgb_length(msg), src_oa, oa);
return -1;
}
}
@@ -1579,36 +1526,17 @@ static int rx_rtp(struct msgb *msg)
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
return conn->endp->type->dispatch_rtp_cb(msg);
out_free:
msgb_free(msg);
return -1;
}
static void rtp_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *daddr)
{
/* nothing; osmo_io takes care of msgb_free */
if (res < 0) {
struct mgcp_conn_rtp *conn_rtp = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
int priv_nr = osmo_iofd_get_priv_nr(iofd);
char errbuf[129];
strerror_r(-res, errbuf, sizeof(errbuf));
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
osmo_sockaddr_to_str(daddr), errbuf);
}
}
static const struct osmo_io_ops rtp_ioops = {
.recvfrom_cb = rtp_recvfrom_cb,
.sendto_cb = rtp_sendto_cb,
};
/*! bind RTP port to osmo_fd.
* \param[in] source_addr source (local) address to bind on.
* \param[in] fd associated file descriptor.
* \param[in] port to bind on.
* \param[in] dscp IP DSCP value to use.
* \param[in] prio socket priority to use.
* \returns file descriptor on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio)
* \returns 0 on success, -1 on ERROR. */
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio)
{
int rc;
@@ -1616,32 +1544,85 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr
NULL, 0, OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(dscp) |
OSMO_SOCK_F_PRIO(prio));
if (rc < 0) {
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%d).\n",
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
source_addr, port);
return -1;
}
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%d).\n", source_addr, port);
fd->fd = rc;
LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
return rc;
return 0;
}
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
/* 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) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTP port: %s:%d\n",
source_addr, rtp_end->local_port);
goto cleanup0;
}
if (mgcp_create_bind(source_addr, &rtp_end->rtcp, rtp_end->local_port + 1,
cfg->endp_dscp, cfg->endp_priority) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTCP port: %s:%d\n",
source_addr, rtp_end->local_port + 1);
goto cleanup1;
}
if (osmo_fd_register(&rtp_end->rtp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTP port %d\n",
rtp_end->local_port);
goto cleanup2;
}
if (osmo_fd_register(&rtp_end->rtcp) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTCP port %d\n",
rtp_end->local_port + 1);
goto cleanup3;
}
return 0;
cleanup3:
osmo_fd_unregister(&rtp_end->rtp);
cleanup2:
close(rtp_end->rtcp.fd);
rtp_end->rtcp.fd = -1;
cleanup1:
close(rtp_end->rtp.fd);
rtp_end->rtp.fd = -1;
cleanup0:
return -1;
}
/*! bind RTP port to endpoint/connection.
* \param[in] conn associated RTP connection.
* \param[in] endp endpoint that holds the RTP connection.
* \param[in] rtp_port port number to bind on.
* \param[in] conn associated RTP connection.
* \returns 0 on success, -1 on ERROR. */
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn)
{
char name[512];
struct mgcp_conn *conn = conn_rtp->conn;
struct mgcp_config *cfg = conn->endp->trunk->cfg;
struct mgcp_rtp_end *end = &conn_rtp->end;
int rc, rtp_fd, rtcp_fd;
struct mgcp_rtp_end *end;
snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id);
snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
rtp_port, mgcp_conn_dump(conn->conn));
if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
(end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%u was already bound\n", rtp_port);
/* Double bindings should never occour! Since we always allocate
* connections dynamically and free them when they are not
* needed anymore, there must be no previous binding leftover.
@@ -1651,55 +1632,25 @@ int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
}
end->local_port = rtp_port;
end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
if (!end->rtp)
goto free_iofd_ret;
osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
end->rtcp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
if (!end->rtcp)
goto free_iofd_ret;
osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
osmo_fd_setup(&end->rtp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
osmo_fd_setup(&end->rtcp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
rc = mgcp_create_bind(end->local_addr, end->local_port, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTP port: %s:%d\n", end->local_addr, end->local_port);
goto free_iofd_ret;
}
rtp_fd = rc;
rc = mgcp_create_bind(end->local_addr, end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTCP port: %s:%d\n", end->local_addr, end->local_port + 1);
goto cleanup1;
}
rtcp_fd = rc;
if (osmo_iofd_register(end->rtp, rtp_fd) < 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTP port %d\n", end->local_port);
goto cleanup2;
}
if (osmo_iofd_register(end->rtcp, rtcp_fd) != 0) {
LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTCP port %d\n", end->local_port + 1);
goto cleanup3;
}
return 0;
cleanup3:
osmo_iofd_unregister(end->rtp);
cleanup2:
close(rtcp_fd);
cleanup1:
close(rtp_fd);
free_iofd_ret:
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
}
/*! free allocated RTP and RTCP ports.
* \param[in] end RTP end */
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp.fd != -1) {
osmo_fd_unregister(&end->rtp);
close(end->rtp.fd);
end->rtp.fd = -1;
}
if (end->rtcp.fd != -1) {
osmo_fd_unregister(&end->rtcp);
close(end->rtcp.fd);
end->rtcp.fd = -1;
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -34,6 +34,7 @@
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_protocol.h>
#include <osmocom/mgcp_client/fmtp.h>
#include <errno.h>
#include <stdlib.h>
@@ -55,7 +56,7 @@ struct sdp_rtp_map {
};
struct sdp_fmtp_param {
int payload_type;
struct mgcp_codec_param param;
const char *fmtp;
};
@@ -195,11 +196,7 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
{
char *str;
char *str_ptr;
char *param_str;
unsigned int pt;
unsigned int count = 0;
char delimiter;
unsigned int amr_octet_aligned;
memset(fmtp_param, 0, sizeof(*fmtp_param));
@@ -218,40 +215,13 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
goto error;
fmtp_param->payload_type = pt;
/* Advance pointer to the beginning of the parameter section and
* tokenize string */
/* Advance pointer to the beginning of the parameter section */
str_ptr = strstr(str_ptr, " ");
if (!str_ptr)
goto error;
str_ptr++;
param_str = strtok(str_ptr, " ");
if (!param_str)
goto exit;
while (1) {
/* Make sure that we don't get trapped in an endless loop */
if (count > 256)
goto error;
/* Chop off delimiters ';' at the end */
delimiter = str_ptr[strlen(str_ptr) - 1];
if (delimiter == ';' || delimiter == ',')
str_ptr[strlen(str_ptr) - 1] = '\0';
/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
fmtp_param->param.amr_octet_aligned_present = true;
fmtp_param->param.amr_octet_aligned = false;
if (amr_octet_aligned == 1)
fmtp_param->param.amr_octet_aligned = true;
}
param_str = strtok(NULL, " ");
if (!param_str)
break;
count++;
}
fmtp_param->fmtp = talloc_strdup(ctx, str_ptr);
exit:
talloc_free(str);
@@ -299,43 +269,50 @@ static int audio_ip_from_sdp(struct osmo_sockaddr *dst_addr, char *sdp)
/* Pick optional fmtp parameters by payload type, if there are no fmtp
* parameters, a nullpointer is returned */
static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
static const char *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
{
unsigned int i;
for (i = 0; i < fmtp_params_len; i++) {
if (fmtp_params[i].payload_type == pt)
return &fmtp_params[i].param;
return fmtp_params[i].fmtp;
}
return NULL;
}
/*! Analyze SDP input string.
* \param[inout] p provided memory to store the parsing results.
* \param[in] endp trunk endpoint.
* \param[out] conn associated rtp connection.
* \param[out] caller provided memory to store the parsing results.
*
* Note: In conn (conn->end) the function returns the packet duration,
* rtp port, rtcp port and the codec information.
* \returns 0 on success, -1 on failure. */
int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
{
OSMO_ASSERT(p);
struct mgcp_parse_sdp *sdp = &p->sdp;
struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
unsigned int codecs_used = 0;
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
unsigned int fmtp_used = 0;
struct mgcp_codec_param *codec_param;
char ipbuf[INET6_ADDRSTRLEN];
char *line;
unsigned int i;
void *tmp_ctx = talloc_new(NULL);
struct mgcp_rtp_end *rtp;
int payload_type;
int ptime, ptime2 = 0;
char audio_name[64];
int port, rc;
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
OSMO_ASSERT(p);
rtp = &conn->end;
memset(&codecs, 0, sizeof(codecs));
mgcp_parse_sdp_init(sdp);
for_each_line(line, p->save) {
switch (line[0]) {
@@ -353,19 +330,19 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
if (ptime2 > 0 && ptime2 != ptime)
sdp->ptime = 0;
rtp->packet_duration_ms = 0;
else
sdp->ptime = ptime;
rtp->packet_duration_ms = ptime;
break;
}
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
sdp->maxptime = ptime2;
rtp->maximum_packet_time = ptime2;
break;
}
if (strncmp("a=fmtp:", line, 6) == 0) {
rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
if (rc >= 0)
fmtp_used++;
break;
@@ -374,23 +351,33 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
break;
case 'm':
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
if (rc == 1)
sdp->rtp_port = port;
if (rc == 1) {
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
rtp->rtcp_port = htons(port + 1);
}
rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
rc = pt_from_sdp(conn->conn, codecs,
ARRAY_SIZE(codecs), line);
if (rc > 0)
codecs_used = rc;
break;
case 'c':
if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
talloc_free(tmp_ctx);
return -1;
}
break;
default:
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d on %s\n",
line[0], line[0], p->epname);
if (endp)
/* TODO: Check spec: We used the bare endpoint number before,
* now we use the endpoint name as a whole? Is this allowed? */
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d on %s\n",
line[0], line[0], endp->name);
else
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d\n",
line[0], line[0]);
break;
}
}
@@ -403,24 +390,27 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
/* Store parsed codec information */
for (i = 0; i < codecs_used; i++) {
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
const char *fmtp = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
rc = mgcp_codec_add2(conn, codecs[i].payload_type, codecs[i].map_line, fmtp);
if (rc < 0)
LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
}
talloc_free(tmp_ctx);
LOGP(DLMGCP, LOGL_NOTICE,
"%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
rtp->packet_duration_ms);
if (codecs_used == 0)
LOGPC(DLMGCP, LOGL_NOTICE, "none");
for (i = 0; i < codecs_used; i++) {
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
sdp->cset.codecs[i].payload_type,
strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
LOGPC(DLMGCP, LOGL_NOTICE, " ");
LOGPC(DLMGCP, LOGL_NOTICE, " %d=%s%s%s%s",
rtp->codecs[i].payload_type,
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown",
rtp->codecs[i].fmtp[0] ? ",fmtp='" : "",
rtp->codecs[i].fmtp,
rtp->codecs[i].fmtp[0] ? "'" : "");
}
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
@@ -428,35 +418,34 @@ int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
}
/* Add rtpmap string to the sdp payload, but only when the payload type falls
* into the dynamic payload type range */
static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name)
{
int rc;
if (payload_type >= 96 && payload_type <= 127) {
if (!audio_name)
return -EINVAL;
rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n", payload_type, audio_name);
if (rc < 0)
return -EINVAL;
}
return 0;
}
/* Add audio strings to sdp payload */
static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
/* Add all codecs related lines to SDP payload */
static int add_codecs(struct msgb *sdp, const struct mgcp_conn_rtp *conn)
{
int rc;
unsigned int i;
int local_port;
struct mgcp_trunk *trunk = conn->conn->endp->trunk;
if (!conn->end.codecs_assigned)
return 0;
/* Compose 'm=audio 1234 RTP/AVP 112 96 3' line, with
* - local RTP port
* - a list of all assigned payload type numbers
*/
if (mgcp_conn_rtp_is_osmux(conn))
local_port = trunk->cfg->osmux.local_port;
else
local_port = conn->end.local_port;
rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
if (rc < 0)
return -EINVAL;
for (i = 0; i < payload_types_len; i++) {
rc = msgb_printf(sdp, " %d", payload_types[i]);
for (i = 0; i < conn->end.codecs_assigned; i++) {
const struct mgcp_rtp_codec *c = &conn->end.codecs[i];
rc = msgb_printf(sdp, " %d", c->payload_type);
if (rc < 0)
return -EINVAL;
}
@@ -465,31 +454,45 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
if (rc < 0)
return -EINVAL;
return 0;
}
/* Compose 'a=rtpmap:N FOO' lines for codecs in above list that require it.
* e.g. GSM-FR is implicitly defined by payload type number 3, so it is enough to list 3 above;
* AMR needs a line like 'a=rtpmap:112 AMR/8000/1' in addition to listing 112 above.
*/
for (i = 0; i < conn->end.codecs_assigned; i++) {
const struct mgcp_rtp_codec *c = &conn->end.codecs[i];
if (!c->audio_name[0])
continue;
/* Add fmtp strings to sdp payload */
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
{
unsigned int i;
int rc;
for (i = 0; i < fmtp_params_len; i++) {
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
if (rc < 0)
return -EINVAL;
/* Add amr octet align parameter */
if (fmtp_params[i].param.amr_octet_aligned_present) {
if (fmtp_params[i].param.amr_octet_aligned)
rc = msgb_printf(sdp, " octet-align=1");
else
rc = msgb_printf(sdp, " octet-align=0");
if (rc < 0)
/* Dynamic payload type numbers need explicit rtpmap defining the codec by "subtype name" like "AMR" or
* "GSM-HR-08". Others are defined implicitly, like GSM-FR by payload type number 3.
*
* Also, if the trunk is configured as "no sdp audio-payload send-name", omit all rtpmap lines.
*/
if (c->payload_type >= 96 && c->payload_type <= 127
&& trunk->audio_send_name) {
if (msgb_printf(sdp, "a=rtpmap:%d %s\r\n", c->payload_type, c->audio_name) < 0)
return -EINVAL;
}
rc = msgb_printf(sdp, "\r\n");
/* Compose 'a=fmtp:N foo=bar' line if fmtp is defined for this codec.
* e.g. AMR has fmtp like 'octet-align=1', 'mode-set=0,2,4,7'.
*/
if (c->fmtp[0]) {
if (msgb_printf(sdp, OSMO_SDP_PREFIX_A_FMTP "%d %s\r\n", c->payload_type, c->fmtp) < 0)
return -EINVAL;
}
else if (c->param_present) {
/* Legacy */
if (msgb_printf(sdp, OSMO_SDP_PREFIX_A_FMTP "%d %s\r\n", c->payload_type,
OSMO_SDP_AMR_SET_OCTET_ALIGN(c->param.amr_octet_aligned))
< 0)
return -EINVAL;
}
}
if (conn->end.packet_duration_ms > 0 && conn->conn->endp->trunk->audio_send_ptime) {
rc = msgb_printf(sdp, "a=ptime:%u\r\n",
conn->end.packet_duration_ms);
if (rc < 0)
return -EINVAL;
}
@@ -507,15 +510,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
const char *addr)
{
const struct mgcp_rtp_codec *codec;
const char *audio_name;
int payload_type;
struct sdp_fmtp_param fmtp_param;
int rc;
int payload_types[1];
int local_port;
struct sdp_fmtp_param fmtp_params[1];
unsigned int fmtp_params_len = 0;
bool addr_is_v6;
OSMO_ASSERT(endp);
@@ -523,11 +518,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
OSMO_ASSERT(sdp);
OSMO_ASSERT(addr);
codec = conn->end.cset.codec;
audio_name = codec->audio_name;
payload_type = codec->payload_type;
addr_is_v6 = osmo_ip_str_type(addr) == AF_INET6;
rc = msgb_printf(sdp,
@@ -542,43 +532,14 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
if (rc < 0)
goto buffer_too_small;
if (payload_type >= 0) {
payload_types[0] = payload_type;
if (mgcp_conn_rtp_is_osmux(conn))
local_port = endp->trunk->cfg->osmux.local_port;
else
local_port = conn->end.local_port;
rc = add_audio(sdp, payload_types, 1, local_port);
if (rc < 0)
goto buffer_too_small;
if (endp->trunk->audio_send_name) {
rc = add_rtpmap(sdp, payload_type, audio_name);
if (rc < 0)
goto buffer_too_small;
}
if (codec->param_present) {
fmtp_param.payload_type = payload_type;
fmtp_param.param = codec->param;
fmtp_params[0] = fmtp_param;
fmtp_params_len = 1;
}
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len);
if (rc < 0)
goto buffer_too_small;
}
if (conn->end.packet_duration_ms > 0 && endp->trunk->audio_send_ptime) {
rc = msgb_printf(sdp, "a=ptime:%u\r\n",
conn->end.packet_duration_ms);
if (rc < 0)
goto buffer_too_small;
}
/* Add all codecs related SDP lines */
rc = add_codecs(sdp, conn);
if (rc < 0)
goto buffer_too_small;
return 0;
buffer_too_small:
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP message too large for buffer\n");
return -1;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -103,7 +103,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
@@ -115,7 +115,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
@@ -127,49 +127,40 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_ADDR0000 \
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_ADDR0000_RET \
"200 18983216 OK\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"527 18983216 FAIL\r\n"
#define MDCX4 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -181,7 +172,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
@@ -193,87 +184,87 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 112\r\n" \
"a=rtpmap:112 AMR\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT1 \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: SENDRECV\r\n" \
"M: SENDRECV\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT2 \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_PT3 \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
/* Test different upper/lower case in options */
#define MDCX4_PT4 \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"m: sendrecv\r\n" \
"m: sendrecv\r" \
"c: 2\r\n" \
"i: %s\r\n" \
"l: A:amr, NT:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_SO \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define MDCX4_RO \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
@@ -306,7 +297,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET \
"200 2 OK\r\n" \
@@ -319,7 +310,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
@@ -331,7 +322,7 @@ static void test_strline(void)
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16002 RTP/AVP 97\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
@@ -344,17 +335,17 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16006 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_ZYN \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"C: 2\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n"
"\n" \
"v=0\r" \
"c=IN IP4 123.12.12.123\r" \
"m=audio 5904 RTP/AVP 97\r" \
"a=rtpmap:97 GSM-EFR/8000\r"
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
@@ -380,7 +371,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_X_OSMO_IGN_RET \
"200 2 OK\r\n" \
@@ -393,95 +384,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16010 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0 \
"CRCX 3 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_RET \
"200 3 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16014 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"m: recvonly\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
#define CRCX_PORT_0_IUFP_RET \
"200 4 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 16016 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX in m=sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX using sendrecv mode in the SDP part */
#define CRCX_PORT_0_IUFP_SENDRECV2 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"a=sendrecv\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
/* Do a CRCX entirely omitting a mode, i.e. implcit sendrecv */
#define CRCX_PORT_0_IUFP_SENDRECV3 \
"CRCX 4 1@mgw MGCP 1.0\r\n" \
"C: 2\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 0 RTP/AVP 96\r\n" \
"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
@@ -538,7 +441,7 @@ static void test_strline(void)
"m=audio 5904 RTP/AVP 18 97\r\n" \
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
@@ -553,7 +456,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
@@ -568,7 +471,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
@@ -583,7 +486,7 @@ static void test_strline(void)
"a=rtpmap:18 G729/8000\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=rtpmap:101 FOO/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
@@ -647,7 +550,7 @@ static void test_strline(void)
"t=0 0\r\n" \
"m=audio 16012 RTP/AVP 111\r\n" \
"a=rtpmap:111 AMR/8000/1\r\n" \
"a=fmtp:111 octet-align=1\r\n" \
"a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
"a=ptime:20\r\n"
#define CRCX_NO_LCO_NO_SDP_RET \
@@ -672,7 +575,7 @@ static void test_strline(void)
"c=IN IP4 123.12.12.123\r\n" \
"m=audio 5904 RTP/AVP 97\r\n" \
"a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:20\r\n"
"a=ptime:40\r\n"
#define CRCX_NULL_RET "502 2 FAIL\r\n"
@@ -720,11 +623,139 @@ 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},
{
"CRCX_EXPLICIT_EP",
/* CRCX for a new endpoint 8@mgw, not using the '*@mgw' wildcard */
"CRCX 101 rtpbridge/8@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 1.2.3.4\r\n"
"m=audio 1234 RTP/AVP 112\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n",
"200 101 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 112\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n"
},
{
"CRCX_TWO_PAYLOADS_1",
"CRCX 102 rtpbridge/*@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 1.2.3.4\r\n"
"m=audio 1234 RTP/AVP 112 3\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n",
"200 102 OK\r\n"
"Z: rtpbridge/2@mgw\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 112 3\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n"
},
{
"CRCX_TWO_PAYLOADS_2",
"CRCX 103 rtpbridge/2@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 1.2.3.4\r\n"
"m=audio 1234 RTP/AVP 3 112\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n",
"200 103 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 16018 RTP/AVP 3 112\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=ptime:20\r\n"
},
{
"CRCX_THREE_PAYLOADS_1",
"CRCX 104 rtpbridge/*@mgw MGCP 1.0\r\n"
"m: recvonly\r\n"
"C: 4\r\n"
"L: p:20\r\n"
"\r\n"
"v=0\r\n"
"c=IN IP4 1.2.3.4\r\n"
"m=audio 1234 RTP/AVP 112 3 111\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=fmtp:112 octet-align=1;mode-set=0,2,4,7\r\n"
"a=rtpmap:111 GSM-HR-08/8000\r\n"
"a=ptime:20\r\n",
"200 104 OK\r\n"
"Z: rtpbridge/3@mgw\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 16020 RTP/AVP 112 3 111\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=fmtp:112 octet-align=1;mode-set=0,2,4,7\r\n"
"a=rtpmap:111 GSM-HR-08/8000\r\n"
"a=ptime:20\r\n"
},
{
"CRCX_THREE_PAYLOADS_2",
"CRCX 105 rtpbridge/3@mgw MGCP 1.0\r\n"
"m: recvonly\r\n"
"C: 4\r\n"
"L: p:20\r\n"
"\r\n"
"v=0\r\n"
"c=IN IP4 1.2.3.4\r\n"
"m=audio 1234 RTP/AVP 3 112 113\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=fmtp:112 octet-align=1;mode-set=0,2,4,7\r\n"
"a=rtpmap:113 AMR/8000\r\n"
"a=fmtp:113 octet-align=1;mode-set=0,2,4\r\n"
"a=ptime:20\r\n",
"200 105 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 16022 RTP/AVP 3 112 113\r\n"
"a=rtpmap:112 AMR/8000\r\n"
"a=fmtp:112 octet-align=1;mode-set=0,2,4,7\r\n"
"a=rtpmap:113 AMR/8000\r\n"
"a=fmtp:113 octet-align=1;mode-set=0,2,4\r\n"
"a=ptime:20\r\n"
},
};
static const struct mgcp_test retransmit[] = {
@@ -755,13 +786,12 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
static int dummy_packets = 0;
/* override and forward */
int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
uint32_t dest_host =
htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
const uint8_t *buf = msgb_data(msg);
size_t len = msgb_length(msg);
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
if (len == sizeof(rtp_dummy_payload)
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
@@ -775,8 +805,6 @@ int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags,
OSMO_ASSERT(dest_host);
OSMO_ASSERT(dest_port);
msgb_free(msg);
return len;
}
@@ -928,7 +956,7 @@ static void test_messages(void)
struct msgb *msg;
printf("\n================================================\n");
printf("Testing %s\n", t->name);
printf("Testing %s() %s\n", __func__, t->name);
dummy_packets = 0;
@@ -943,6 +971,7 @@ static void test_messages(void)
}
} else if (check_response(msg->data, t->exp_resp) != 0) {
printf("%s failed.\n", t->name);
fflush(stdout);
OSMO_ASSERT(false);
}
@@ -965,7 +994,7 @@ static void test_messages(void)
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, "1");
conn = mgcp_conn_get_rtp(endp, "1");
if (conn) {
OSMO_ASSERT(conn);
@@ -1023,15 +1052,18 @@ static void test_messages(void)
fprintf(stderr, "endpoint:%s: "
"payload type %d (expected %d)\n",
last_endpoint,
conn->end.cset.codec->payload_type, t->ptype);
conn->end.codec->payload_type, t->ptype);
if (t->ptype != PTYPE_IGNORE)
OSMO_ASSERT(conn->end.cset.codec->payload_type ==
OSMO_ASSERT(conn->end.codec->payload_type ==
t->ptype);
/* Reset them again for next test */
conn->end.cset.codec->payload_type = PTYPE_NONE;
conn->end.codec->payload_type = PTYPE_NONE;
}
fflush(stdout);
fflush(stderr);
}
mgcp_endpoints_release(trunk);
@@ -1060,7 +1092,7 @@ static void test_retransmission(void)
struct msgb *msg;
printf("\n================================================\n");
printf("Testing %s\n", t->name);
printf("Testing %s() %s\n", __func__, t->name);
inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
@@ -1090,6 +1122,9 @@ static void test_retransmission(void)
OSMO_ASSERT(false);
}
msgb_free(msg);
fflush(stdout);
fflush(stderr);
}
mgcp_endpoints_release(trunk);
@@ -1208,9 +1243,7 @@ static void test_packet_loss_calc(void)
_conn =
mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
state = &conn->state;
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
@@ -1230,7 +1263,7 @@ static void test_packet_loss_calc(void)
pl_test_dat[i].expected);
}
mgcp_endp_free_conn_all(&endp);
mgcp_conn_free_all(&endp);
}
talloc_free(trunk);
@@ -1461,13 +1494,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
rtp = &conn->end;
OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->cset.codec = &rtp->cset.codecs[0];
OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->codec = &rtp->codecs[0];
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
struct rtp_packet_info *info = test_rtp_packets1 + i;
@@ -1479,6 +1512,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
OSMO_ASSERT(info->len >= 0);
msg->l3h = msgb_put(msg, info->len);
memcpy((char*)msgb_l3(msg), info->data, info->len);
mgcp_rtp_end_config(&endp, 1, rtp);
mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
@@ -1512,7 +1546,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
}
force_monotonic_time_us = -1;
mgcp_endp_free_conn_all(&endp);
mgcp_conn_free_all(&endp);
talloc_free(trunk);
talloc_free(cfg);
}
@@ -1547,9 +1581,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 2@mgw with three codecs, last one ignored */
last_endpoint[0] = '\0';
@@ -1563,9 +1597,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 3@mgw with no codecs, check for PT == 0 */
/* Note: It usually makes no sense to leave the payload type list
@@ -1584,9 +1618,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
/* Allocate 4@mgw with a single codec */
last_endpoint[0] = '\0';
@@ -1600,9 +1634,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
last_endpoint[0] = '\0';
@@ -1616,9 +1650,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
inp = create_msg(MDCX_NAT_DUMMY, conn_id);
last_endpoint[0] = '\0';
@@ -1628,9 +1662,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 3);
OSMO_ASSERT(conn->end.codec->payload_type == 3);
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
memset(&addr, 0, sizeof(addr));
inet_aton("8.8.8.8", &addr);
@@ -1645,7 +1679,7 @@ static void test_multilple_codec(void)
talloc_free(endp->last_response);
talloc_free(endp->last_trans);
endp->last_response = endp->last_trans = NULL;
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(!conn);
last_endpoint[0] = '\0';
@@ -1659,9 +1693,9 @@ static void test_multilple_codec(void)
OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
mgcp_endpoints_release(trunk);
talloc_free(cfg);
@@ -1688,7 +1722,7 @@ static void test_no_cycle(void)
_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
"test-connection");
OSMO_ASSERT(_conn);
conn = mgcp_endp_get_conn_rtp(endp, _conn->id);
conn = mgcp_conn_get_rtp(endp, _conn->id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->state.stats.initialized == 0);
@@ -1719,6 +1753,7 @@ static void test_no_cycle(void)
talloc_free(cfg);
}
/* Set audio_send_name=0 and verify that a=rtpmap: entries are omitted. */
static void test_no_name(void)
{
struct mgcp_trunk *trunk;
@@ -2194,7 +2229,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
int payload_type_conn_dst;
printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
if (expect->payload_type_map[index_conn_src] == -EINVAL
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
printf(" codec decision failed (expected)!\n");
@@ -2204,19 +2239,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
}
} else {
printf(" Codec decision result:\n");
if (conn[index_conn_src].end.cset.codec) {
payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
if (conn[index_conn_src].end.codec) {
payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src);
index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
} else {
payload_type_conn_src = -EINVAL;
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
}
if (conn[index_conn_dst].end.cset.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
if (conn[index_conn_dst].end.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name,
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
payload_type_conn_dst);
} else {
payload_type_conn_dst = -EINVAL;
@@ -2264,8 +2299,8 @@ static void test_mgcp_codec_decide(void)
if (!codec->audio_name)
break;
rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, codec->payload_type,
codec->audio_name, codec->param);
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
codec->param);
printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
codec->param ?
@@ -2331,7 +2366,7 @@ void test_conn_id_matching(void)
for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
const char *needle = conn_id_request[i];
printf("needle='%s' ", needle);
conn_match = mgcp_endp_get_conn(&endp, needle);
conn_match = mgcp_conn_get(&endp, needle);
OSMO_ASSERT(conn_match);
printf("found '%s'\n", conn_match->id);
OSMO_ASSERT(conn_match == conn);
@@ -2437,6 +2472,13 @@ int main(int argc, char **argv)
void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
log_set_print_level(osmo_stderr_target, 1);
log_set_print_category(osmo_stderr_target, 1);
log_set_print_category_hex(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 1);
log_set_category_filter(osmo_stderr_target, DLMGCP, true, LOGL_DEBUG);
test_strline();
test_values();

View File

@@ -13,7 +13,7 @@ line: ''
line: ''
================================================
Testing AUEP1
Testing test_messages() AUEP1
creating message from statically defined input:
---------8<---------
AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0
@@ -25,7 +25,7 @@ Response matches our expectations.
(response does not contain a connection id)
================================================
Testing AUEP2
Testing test_messages() AUEP2
creating message from statically defined input:
---------8<---------
AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0
@@ -37,7 +37,7 @@ Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX1
Testing test_messages() MDCX1
creating message from statically defined input:
---------8<---------
MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0
@@ -49,7 +49,7 @@ Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX2
Testing test_messages() MDCX2
creating message from statically defined input:
---------8<---------
MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0
@@ -61,7 +61,7 @@ Response matches our expectations.
(response does not contain a connection id)
================================================
Testing CRCX
Testing test_messages() CRCX
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
@@ -73,7 +73,7 @@ v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:20
a=ptime:40
---------8<---------
checking response:
@@ -83,7 +83,7 @@ Response matches our expectations.
Dummy packets: 2
================================================
Testing MDCX3
Testing test_messages() MDCX3
creating message from statically defined input:
---------8<---------
MDCX 18983215 1@mgw MGCP 1.0
@@ -97,46 +97,44 @@ Response matches our expectations.
Dummy packets: 2
================================================
Testing MDCX4_ADDR000
Testing test_messages() MDCX4_ADDR000
creating message from statically defined input:
---------8<---------
MDCX 18983216 1@mgw MGCP 1.0
M: sendrecv
C: 2
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 0.0.0.0
c=IN IP4 0.0.0.0
t=0 0
m=audio 4441 RTP/AVP 99
a=ptime:20
a=rtpmap:99 AMR/8000
a=ptime:40
---------8<---------
using message with patched conn_id for comparison
checking response:
using message as statically defined for comparison
(response contains a connection id)
Response matches our expectations.
(response does not contain a connection id)
Testing MDCX4
================================================
Testing test_messages() MDCX4
creating message from statically defined input:
---------8<---------
M: sendrecv
C: 2
MDCX 18983217 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
a=ptime:20
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -146,22 +144,21 @@ Response matches our expectations.
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
Testing MDCX4_PT1
================================================
Testing test_messages() MDCX4_PT1
creating message from statically defined input:
M: SENDRECV
C: 2
---------8<---------
MDCX 18983218 1@mgw MGCP 1.0
M: SENDRECV
C: 2
I: %s
L: p:20-40, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
a=ptime:20
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
@@ -171,22 +168,21 @@ Response matches our expectations.
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
Testing MDCX4_PT2
Dummy packets: 2
================================================
Testing test_messages() MDCX4_PT2
M: sendrecv
C: 2
creating message from statically defined input:
---------8<---------
MDCX 18983219 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20-20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
a=ptime:20
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
@@ -196,22 +192,21 @@ Response matches our expectations.
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
Testing MDCX4_PT3
(response contains a connection id)
Dummy packets: 2
================================================
M: sendrecv
C: 2
Testing test_messages() MDCX4_PT3
creating message from statically defined input:
---------8<---------
MDCX 18983220 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: a:AMR, nt:IN
v=0
a=ptime:20
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
@@ -221,22 +216,21 @@ Response matches our expectations.
---------8<---------
checking response:
using message with patched conn_id for comparison
Testing MDCX4_PT4
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
m: sendrecv
c: 2
================================================
Testing test_messages() MDCX4_PT4
creating message from statically defined input:
---------8<---------
MDCX 18983221 1@mgw MGCP 1.0
m: sendrecv
c: 2
i: %s
l: A:amr, NT:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
@@ -246,22 +240,21 @@ Response matches our expectations.
---------8<---------
checking response:
Testing MDCX4_SO
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
M: sendonly
C: 2
================================================
Testing test_messages() MDCX4_SO
creating message from statically defined input:
---------8<---------
MDCX 18983222 1@mgw MGCP 1.0
M: sendonly
C: 2
I: %s
L: p:20, a:AMR, nt:IN
a=ptime:20
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
@@ -270,12 +263,11 @@ Response matches our expectations.
a=rtpmap:99 AMR/8000
a=ptime:40
Testing MDCX4_RO
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
M: recvonly
C: 2
(response contains a connection id)
================================================
Testing test_messages() MDCX4_RO
@@ -287,7 +279,7 @@ Response matches our expectations.
I: %s
L: p:20, a:AMR, nt:IN
Testing DLCX
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
@@ -301,18 +293,12 @@ Response matches our expectations.
DLCX 7 1@mgw MGCP 1.0
I: %s
C: 2
Testing CRCX_ZYN
---------8<---------
checking response:
CRCX 2 1@mgw MGCP 1.0
M: recvonly
C: 2
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing test_messages() CRCX_ZYN
@@ -321,7 +307,7 @@ Response matches our expectations.
CRCX 2 1@mgw MGCP 1.0
M: recvonly
C: 2
Testing EMPTY
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
@@ -329,7 +315,7 @@ creating message from statically defined input:
---------8<---------
checking response:
using message with patched conn_id for comparison
Testing SHORT1
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
@@ -341,7 +327,7 @@ Response matches our expectations.
---------8<---------
Testing SHORT2
================================================
Testing test_messages() SHORT1
creating message from statically defined input:
---------8<---------
@@ -352,7 +338,7 @@ Response matches our expectations.
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
Testing SHORT3
================================================
Testing test_messages() SHORT2
creating message from statically defined input:
@@ -363,7 +349,7 @@ Response matches our expectations.
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
Testing SHORT4
================================================
Testing test_messages() SHORT3
creating message from statically defined input:
@@ -374,7 +360,7 @@ Response matches our expectations.
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
Testing RQNT1
================================================
Testing test_messages() SHORT4
creating message from statically defined input:
@@ -388,7 +374,7 @@ Response matches our expectations.
================================================
Testing test_messages() RQNT1
Testing RQNT2
creating message from statically defined input:
---------8<---------
RQNT 186908780 1@mgw MGCP 1.0
X: B244F267488
@@ -402,7 +388,7 @@ Response matches our expectations.
================================================
Testing test_messages() RQNT2
Testing DLCX
creating message from statically defined input:
---------8<---------
RQNT 186908781 1@mgw MGCP 1.0
X: ADD4F26746F
@@ -416,7 +402,7 @@ Response matches our expectations.
================================================
Testing test_messages() DLCX
Testing CRCX
creating message from statically defined input:
---------8<---------
DLCX 7 1@mgw MGCP 1.0
I: %s
@@ -428,7 +414,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing test_messages() CRCX
creating message from statically defined input:
---------8<---------
@@ -438,7 +424,7 @@ Response matches our expectations.
L: p:20
v=0
Testing MDCX3
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:40
@@ -452,7 +438,7 @@ Response matches our expectations.
================================================
Testing test_messages() MDCX3
Testing DLCX
creating message from statically defined input:
---------8<---------
MDCX 18983215 1@mgw MGCP 1.0
I: %s
@@ -466,7 +452,7 @@ Response matches our expectations.
================================================
Testing test_messages() DLCX
Testing CRCX
creating message from statically defined input:
---------8<---------
DLCX 7 1@mgw MGCP 1.0
I: %s
@@ -480,7 +466,7 @@ Response matches our expectations.
================================================
Testing test_messages() CRCX
Testing CRCX
creating message from statically defined input:
---------8<---------
CRCX 2 6@mgw MGCP 1.0
M: recvonly
@@ -493,7 +479,7 @@ v=0
(response contains a connection id)
================================================
a=ptime:20
Testing test_messages() CRCX
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
@@ -503,7 +489,7 @@ Response matches our expectations.
X-Osmo-IGN: C foo
v=0
Testing MDCX_TOO_LONG_CI
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:40
@@ -516,7 +502,7 @@ Response matches our expectations.
Dummy packets: 2
================================================
Testing CRCX
Testing test_messages() MDCX_TOO_LONG_CI
creating message from statically defined input:
---------8<---------
MDCX 18983224 1@mgw MGCP 1.0
@@ -540,7 +526,7 @@ Response matches our expectations.
v=0
c=IN IP4 123.12.12.123
Testing AUEP_NULL
m=audio 5904 RTP/AVP 111
a=rtpmap:111 AMR/8000/1
a=ptime:20
a=fmtp:111 mode-change-capability=2; octet-align=1
@@ -552,7 +538,7 @@ Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
Testing CRCX_NULL
================================================
Testing test_messages() AUEP_NULL
creating message from statically defined input:
---------8<---------
@@ -564,7 +550,7 @@ v=0
Response matches our expectations.
(response does not contain a connection id)
a=ptime:20
================================================
Testing test_messages() CRCX_NULL
creating message from statically defined input:
---------8<---------
@@ -573,7 +559,7 @@ Response matches our expectations.
C: 2
L: p:20
Testing MDCX_NULL
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
@@ -586,7 +572,7 @@ Response matches our expectations.
(response does not contain a connection id)
================================================
Testing DLCX_NULL
Testing test_messages() MDCX_NULL
creating message from statically defined input:
---------8<---------
MDCX 9 null@mgw MGCP 1.0
@@ -600,7 +586,7 @@ Response matches our expectations.
================================================
Testing test_messages() DLCX_NULL
Testing RQNT_NULL
creating message from statically defined input:
---------8<---------
DLCX 8 null@mgw MGCP 1.0
I: %s
@@ -614,18 +600,18 @@ Response matches our expectations.
================================================
Testing test_messages() RQNT_NULL
Testing CRCX_PORT_0
creating message from statically defined input:
---------8<---------
RQNT 186908782 null@mgw MGCP 1.0
CRCX 3 1@mgw MGCP 1.0
X: B244F267488
S: D/9
---------8<---------
checking response:
using message as statically defined for comparison
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing test_messages() CRCX_EXPLICIT_EP
creating message from statically defined input:
@@ -633,20 +619,21 @@ checking response:
CRCX 101 rtpbridge/8@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
Testing CRCX_PORT_0_IUFP
c=IN IP4 1.2.3.4
m=audio 1234 RTP/AVP 112
a=rtpmap:112 AMR/8000
CRCX 4 1@mgw MGCP 1.0
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
(response contains a connection id)
Dummy packets: 2
================================================
Testing test_messages() CRCX_TWO_PAYLOADS_1
creating message from statically defined input:
@@ -654,20 +641,21 @@ checking response:
CRCX 102 rtpbridge/*@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
Testing CRCX_PORT_0_IUFP_SENDRECV
c=IN IP4 1.2.3.4
m=audio 1234 RTP/AVP 112 3
a=rtpmap:112 AMR/8000
CRCX 4 1@mgw MGCP 1.0
M: sendrecv
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
(response contains a connection id)
Dummy packets: 2
================================================
Testing test_messages() CRCX_TWO_PAYLOADS_2
creating message from statically defined input:
@@ -675,20 +663,23 @@ checking response:
CRCX 103 rtpbridge/2@mgw MGCP 1.0
m: recvonly
C: 2
L: p:20
v=0
Testing CRCX_PORT_0_IUFP_SENDRECV2
c=IN IP4 1.2.3.4
m=audio 1234 RTP/AVP 3 112
a=rtpmap:112 AMR/8000
CRCX 4 1@mgw MGCP 1.0
C: 2
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
c=IN IP4 123.12.12.123
a=sendrecv
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
(response contains a connection id)
Dummy packets: 2
================================================
Testing test_messages() CRCX_THREE_PAYLOADS_1
creating message from statically defined input:
---------8<---------
CRCX 104 rtpbridge/*@mgw MGCP 1.0
@@ -696,19 +687,24 @@ checking response:
C: 4
L: p:20
v=0
c=IN IP4 1.2.3.4
m=audio 1234 RTP/AVP 112 3 111
Testing CRCX_PORT_0_IUFP_SENDRECV3
a=rtpmap:112 AMR/8000
a=fmtp:112 octet-align=1;mode-set=0,2,4,7
a=rtpmap:111 GSM-HR-08/8000
CRCX 4 1@mgw MGCP 1.0
C: 2
a=ptime:20
---------8<---------
checking response:
using message with patched conn_id for comparison
Response matches our expectations.
c=IN IP4 123.12.12.123
m=audio 0 RTP/AVP 96
a=rtpmap:96 VND.3GPP.IUFP/16000
(response contains a connection id)
Dummy packets: 2
================================================
Testing test_messages() CRCX_THREE_PAYLOADS_2
creating message from statically defined input:
---------8<---------
CRCX 105 rtpbridge/3@mgw MGCP 1.0
m: recvonly
@@ -716,9 +712,10 @@ checking response:
L: p:20
v=0
c=IN IP4 1.2.3.4
m=audio 1234 RTP/AVP 3 112 113
a=rtpmap:112 AMR/8000
Testing CRCX
a=fmtp:112 octet-align=1;mode-set=0,2,4,7
a=rtpmap:113 AMR/8000
a=fmtp:113 octet-align=1;mode-set=0,2,4
a=ptime:20
@@ -730,7 +727,7 @@ v=0
(response contains a connection id)
Dummy packets: 2
a=ptime:20
================================================
Testing test_retransmission() CRCX
creating message from statically defined input:
---------8<---------
@@ -748,7 +745,7 @@ v=0
---------8<---------
checking response:
using message with patched conn_id for comparison
a=ptime:20
Response matches our expectations.
Re-transmitting CRCX
creating message from statically defined input:
---------8<---------
@@ -756,7 +753,7 @@ using message with patched conn_id for comparison
m: recvonly
C: 2
L: p:20
Testing RQNT1
v=0
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
@@ -780,7 +777,7 @@ using message as statically defined for comparison
checking response:
using message as statically defined for comparison
Response matches our expectations.
Testing RQNT2
Re-transmitting RQNT1
creating message from statically defined input:
---------8<---------
RQNT 186908780 1@mgw MGCP 1.0
@@ -804,7 +801,7 @@ using message as statically defined for comparison
checking response:
using message as statically defined for comparison
Response matches our expectations.
Testing MDCX3
Re-transmitting RQNT2
creating message from statically defined input:
---------8<---------
RQNT 186908781 1@mgw MGCP 1.0
@@ -826,7 +823,7 @@ using message with patched conn_id for comparison
---------8<---------
checking response:
using message with patched conn_id for comparison
Testing DLCX
Response matches our expectations.
Re-transmitting MDCX3
creating message from statically defined input:
---------8<---------
@@ -860,7 +857,7 @@ v=0
---------8<---------
checking response:
using message as statically defined for comparison
a=ptime:20
Response matches our expectations.
Testing packet loss calculation.
creating message from statically defined input:
---------8<---------
@@ -1314,7 +1311,7 @@ c=IN IP4 123.12.12.123
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 5, Transit = -163760
Testing multiple payload types
a=ptime:20
creating message from statically defined input:
---------8<---------
CRCX 2 1@mgw MGCP 1.0
M: recvonly
@@ -1331,7 +1328,7 @@ m=audio 5904 RTP/AVP 18 97 101
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 2@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1348,7 +1345,7 @@ m=audio 5904 RTP/AVP
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 3@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1365,7 +1362,7 @@ m=audio 5904 RTP/AVP 18
---------8<---------
creating message from statically defined input:
a=ptime:20
---------8<---------
CRCX 2 4@mgw MGCP 1.0
M: recvonly
C: 2
@@ -1447,7 +1444,7 @@ v=0
a=recvonly
---------8<---------
a=ptime:20
Testing no sequence flow on initial packet
Testing no rtpmap name
creating message from statically defined input:
---------8<---------

View File

@@ -571,57 +571,6 @@ static void test_map_str_to_codec(void)
OSMO_ASSERT(map_str_to_codec("AMR-WB####################################################################################################################") == -1);
}
static void test_map_codec_to_pt_and_map_pt_to_codec(void)
{
struct ptmap ptmap[10];
unsigned int ptmap_len;
unsigned int i;
ptmap[0].codec = CODEC_GSMEFR_8000_1;
ptmap[0].pt = 96;
ptmap[1].codec = CODEC_GSMHR_8000_1;
ptmap[1].pt = 97;
ptmap[2].codec = CODEC_AMR_8000_1;
ptmap[2].pt = 98;
ptmap[3].codec = CODEC_AMRWB_16000_1;
ptmap[3].pt = 99;
ptmap_len = 4;
/* Mappings that are covered by the table */
for (i = 0; i < ptmap_len; i++)
printf(" %u => %u\n", ptmap[i].codec, map_codec_to_pt(ptmap, ptmap_len, ptmap[i].codec));
for (i = 0; i < ptmap_len; i++)
printf(" %u <= %u\n", ptmap[i].pt, map_pt_to_codec(ptmap, ptmap_len, ptmap[i].pt));
printf("\n");
/* Map some codecs/payload types from the static range, result must
* always be a 1:1 mapping */
printf(" %u => %u\n", CODEC_PCMU_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_PCMU_8000_1));
printf(" %u => %u\n", CODEC_GSM_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_GSM_8000_1));
printf(" %u => %u\n", CODEC_PCMA_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_PCMA_8000_1));
printf(" %u => %u\n", CODEC_G729_8000_1, map_codec_to_pt(ptmap, ptmap_len, CODEC_G729_8000_1));
printf(" %u <= %u\n", CODEC_PCMU_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_PCMU_8000_1));
printf(" %u <= %u\n", CODEC_GSM_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_GSM_8000_1));
printf(" %u <= %u\n", CODEC_PCMA_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_PCMA_8000_1));
printf(" %u <= %u\n", CODEC_G729_8000_1, map_pt_to_codec(ptmap, ptmap_len, CODEC_G729_8000_1));
printf("\n");
/* Try to do mappings from statically defined range to danymic range and vice versa. This
* is illegal and should result into a 1:1 mapping */
ptmap[3].codec = CODEC_AMRWB_16000_1;
ptmap[3].pt = 2;
ptmap[4].codec = CODEC_PCMU_8000_1;
ptmap[4].pt = 100;
ptmap_len = 5;
/* Apply all mappings again, the illegal ones we defined should result into 1:1 mappings */
for (i = 0; i < ptmap_len; i++)
printf(" %u => %u\n", ptmap[i].codec, map_codec_to_pt(ptmap, ptmap_len, ptmap[i].codec));
for (i = 0; i < ptmap_len; i++)
printf(" %u <= %u\n", ptmap[i].pt, map_pt_to_codec(ptmap, ptmap_len, ptmap[i].pt));
printf("\n");
}
void test_mgcp_client_e1_epname(void)
{
char *epname;
@@ -908,7 +857,6 @@ int main(int argc, char **argv)
test_mgcp_msg();
test_mgcp_client_cancel();
test_sdp_section_start();
test_map_codec_to_pt_and_map_pt_to_codec();
test_map_str_to_codec();
test_mgcp_client_e1_epname();

View File

@@ -128,10 +128,6 @@ test_sdp_section_start() test [18]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 \r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!

View File

@@ -181,35 +181,6 @@ test_sdp_section_start() test [16]:
test_sdp_section_start() test [17]:
test_sdp_section_start() test [18]:
110 => 96
111 => 97
112 => 98
113 => 99
96 <= 110
97 <= 111
98 <= 112
99 <= 113
0 => 0
3 => 3
8 => 8
18 => 18
0 <= 0
3 <= 3
8 <= 8
18 <= 18
110 => 96
111 => 97
112 => 98
113 => 113
0 => 0
96 <= 110
97 <= 111
98 <= 112
2 <= 2
100 <= 100
ds/e1-1/s-15/su64-0@mgw
ds/e1-2/s-14/su32-0@mgw
ds/e1-3/s-13/su32-4@mgw