Compare commits

...

19 Commits

Author SHA1 Message Date
Oliver Smith
2eacae8f2e Bump version: 1.13.1.41-403d5-dirty → 1.14.0
Change-Id: Ib6f5b6ee771adb967fa6cebae03c519839693566
2025-02-12 12:32:06 +01:00
Mychaela N. Falconia
403d5f1489 E1: replace idle_tf_fr[] with a better version
The only truly correct way to pass FR/HR/EFR traffic from an
incoming RTP stream to TRAU-DL frames is to apply the transform
of TS 28.062 section C.3.2.1.1, originally specified for TFO
but also necessary in the non-3GPP-specified case of GSM TrFO
as it happens here.  Unlike the situation with EFR, a FOSS
implementation of TFO transform for FRv1 does exist in Themyscira
libgsmfr2 - however, making these Themyscira codec libraries
usable from mainline Osmocom programs by way of a proposed
libosmocore DSO plugin mechanism, followed by a major redesign
of OsmoMGW-E1 to pass all DL traffic through this TFO transform,
would be a major project, difficult to justify prior to development
of a proper TFO transform for EFR to complement the one for FRv1.
Hence no change is being made currently to the arguably flawed
general architecture of OsmoMGW-E1, which consists of passing
through unaltered all valid codec frames that are received in RTP,
and inserting fixed dummy TRAU-DL frames when no RTP-derived ones
are available.

The original dummy TRAU-DL frame for FRv1 exhibited the following
defects:

* The payload frame transmitted to the MS consisted of all zero
  bits.  Standard type-approved GSM MS would interpret this bit
  pattern as a SID frame, even though the BTS is told via C16 bit
  "this frame is not a SID".  Passing a SID is not inherently bad
  in itself in this context, but a SID with all LARc parameters
  set to 0 is a strange/poor choice.

* The setting of C-bits (defined in TS 48.060 section 5.5.1.1.1)
  was a mish-mash between TRAU-UL and TRAU-DL frame formats,
  thereby not matching the standard TRAU-DL C-bits fill produced
  by osmo_rtp2trau().

The replacement fill frame introduced here differs as follows:

* The payload bit content is the silence frame of GSM 46.011
  Table 1: certainly better than a SID with all LARc parameters
  set to 0, and arguably better than any SID at all.

* The full TRAU-DL frame (C-bits pattern, peculiar ordering of
  D-bits) was generated by passing said silence frame through
  osmo_rtp2trau(), using this ad hoc tool:

https://gitea.osmocom.org/themwi/dummy-dl-frames

Change-Id: I995824586058e4e4ed77e900d4b57e5113f9eff6
2025-02-05 21:37:23 +00:00
Mychaela N. Falconia
f227633959 E1: replace idle_tf_efr[] with a better version
The only truly correct way to pass FR/HR/EFR traffic from an
incoming RTP stream to TRAU-DL frames is to apply the transform
of TS 28.062 section C.3.2.1.1, originally specified for TFO
but also necessary in the non-3GPP-specified case of GSM TrFO
as it happens here.  However, no FOSS or even published-source
implementation of TFO transform for EFR exists at the present time
(no implementations at all are known outside of TRAU DSP firmware),
hence the general architectural approach of OsmoMGW-E1, flawed
as it is, has to remain for now.  This flawed architecture consists
of passing through unaltered all valid codec frames that are
received in RTP, and inserting fixed dummy TRAU-DL frames when no
RTP-derived ones are available.

The original dummy TRAU-DL frame for EFR exhibited the following
defects:

* D1 bit was set to 0, even though TS 48.060 section 5.5.1.1.2
  states it shall be 1;

* All 5 EFR frame CRCs were invalid: each 3-bit CRC was 000, even
  though the correct TS 48.060 section 5.5.1.1.2 CRC from an
  all-zeros payload would be 111;

* Even if the 5 CRCs were fixed, transmitting an EFR frame of all
  zero bits to the MS won't produce good results - it is a bad
  choice of dummy filler;

* The setting of C-bits (defined in TS 48.060 section 5.5.1.1.1)
  was a mish-mash between TRAU-UL and TRAU-DL frame formats,
  thereby not matching the standard TRAU-DL C-bits fill produced
  by osmo_rtp2trau().

The replacement fill frame introduced here differs as follows:

* The payload bit content 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;

* The full TRAU-DL frame (C-bits, CRC etc) was generated by passing
  said EFR DHF through osmo_rtp2trau(), using this ad hoc tool:

https://gitea.osmocom.org/themwi/dummy-dl-frames

Change-Id: I5a33a1c9ddf1372f91870d61b5eafac4729ee458
2025-02-05 21:03:29 +00:00
Mychaela N. Falconia
83c8846728 E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
By changing the white space structure of these hard-coded frames
to only have one leading tab on each line of 8 frame bits, we make
it easier to replace these hard-coded frames with different versions
that are programmatically generated, as will be done in the following
patches.

Change-Id: I3d0c931d4dc3d916ba4c5eb081bea22d9c7144de
2025-02-05 20:08:59 +00:00
Pau Espin Pedrol
78ee99adcf mgw: MDCX: Simplify early return code paths
Change-Id: Icb03a95e34e0c7d9396fefc2e37ee33ab09daa89
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
de4090d920 mgw: Remove wrong TODO comment
The TODO was written because the author had in mind the ptr where the
codec was stored was a MGCP endpoint object, but it is actually an
rtp_end which is an object under conn_rtp, so that's fine already with
current code.

Change-Id: I99d2211e81443883c45cc3fdda10e39a8c152063
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
732cadd2c8 mgw: Decouple SDP parsing step from conn obj update
This allows delaying modification of the conn before full parsing
succeeds.

Change-Id: I4a2aecb542886672c1f586c6607714e0356abe35
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
6747b60a95 mgw: DLCX: Split mgcp header pars parsing into a previous step
Do most of the initial parsing and verification in a prior step, filling
in a "parsed" struct which simplifies logic coming after for different
message types.

Change-Id: I557a3a257ddefedc479a4aff974a74c4e4e2c85d
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
90ae9ed0a2 mgw: MDCX: Split mgcp header pars parsing into a previous step
Do most of the initial parsing and verification in a prior step, filling
in a "parsed" struct which simplifies logic coming after for different
message types.
This commit only modifies stuff enough to work for MDCX.
Further work (commits) will follow for DLCX.

Change-Id: I6ecb41fc2cc737c3a161b6bc98bd08ae01909655
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
206be49c69 mgw: CRCX: Split mgcp header pars parsing into a previous step
Do most of the initial parsing and verification in a prior step, filling
in a "parsed" struct which simplifies logic coming after for different
message types.
This commit only modifies stuff enough to work for CRCX.
Further work (commits) will follow for MDCX and DLCX.

Change-Id: I3ee5158c254213203830fe9c38de11c15b4b19c1
2025-01-21 16:48:52 +01:00
Pau Espin Pedrol
45559e9230 mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
Clean up pointers passed. Rename function since it's clearly operating
on trunk related fields through mutexes.

Change-Id: Ib894afcb61609c247883d5ccdd7b8fbf29b2cbf8
2025-01-14 16:44:33 +01:00
Pau Espin Pedrol
f94b846224 mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
Clean up pointers, join 2 functions only making stuff more confusing.
Rename function to make it clear it operates on a conn_rtp object.

Change-Id: I50a251b66e85ceeeccb30dcd1813863d7c754961
2025-01-14 16:44:28 +01:00
Pau Espin Pedrol
3ea3a69821 mgw: Simplify and redo code around ssrc patch feature
The previous logic to configure SSRC patching was over complex and
confusing, with even some broken logic like "patch only once", which is
not really needed. Hence, simplify the internal logic to either patch
SSRC always or don't do it, based on VTY configuration.

The "force SSRC" feature was added in
db2d431697 and further changed in
e2292f3aa1, due to the need for nanoBTS to
always keep the same SSRC on received packets. However, it makes no
sense that is actually needed only once: if remote end changed several
times, then we should keep patching in that case.

This change allows getting rid of confusing applying of settings at a
later time through mgcp_rtp_end_config(), which is no longer needed and
can be dropped, simplifying steps during CRCX/MDCX/DLCX.

Change-Id: Ib7216a775f4ad126e62b9e99aff381fd45015819
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
46ddc65626 mgw: Move several params setting to mgcp_rtp_end_init()
There's no need to set those 2 params later on, simply set them during
init() to simplify code.

Change-Id: I38e2cfbe03c1e2de48e48f30a04af746bc2368a4
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
71f313749e mgw: Move force_ptime logic outside of main CRCX func handler
Apply the forced value automatically during init, and then only
override it based on received input from MGCP when it has not been
forced by VTY config.

Change-Id: I02a92a090887caa8e05917a44c8b2351fa7b9b50
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
80a5abbbe3 mgw: Cleanup rtp_endp fields in its own function
Change-Id: I0b2ccb94129dc7aed6fe13bb20f9910a53d8a41e
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
ba812f7e86 mgw: Introduce struct mgcp_codecset struct
We do tons of operations on 3 fields (array of codecs, len of array,
selected code) which can be isolated.
Right now, we are using APIs which somehow require structs 2-3 levels of
encapsulation above the ones really required, which makes all code
totally entangled, difficult to understand and prone to errors when
changing stuff in deeply nested structs.
A prove of this is how this patch affects a lot of lines in lots of
places.

Change-Id: Id7db7ab01d56b7fa2415123b604375e48c82ab25
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
345c37a543 mgw: Introduce mgcp_rtp_end_init()
Change-Id: I29f57dfde60e3134f1db422dc63e7c58d3db7d54
2025-01-07 11:47:56 +01:00
Pau Espin Pedrol
b3457cd250 mgw: Split mgcp_rtp_end to its own file
Preparation path to add an init function and start untangling related
code.

While at it, move definition of struct mgcp_rtp_codec to the mgcp_codec.h where it belongs.

Change-Id: Id1b6cab57e44ad4859bde8212d0ac9f7146d7198
2025-01-07 11:47:56 +01:00
27 changed files with 1014 additions and 860 deletions

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.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.6.0)
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)
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"

49
debian/changelog vendored
View File

@@ -1,3 +1,52 @@
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 ]

6
debian/control vendored
View File

@@ -6,9 +6,9 @@ Build-Depends: debhelper (>= 10),
dh-autoreconf,
pkg-config,
autotools-dev,
libosmocore-dev (>= 1.10.0),
libosmo-netif-dev (>= 1.5.0),
libosmo-abis-dev (>= 1.6.0),
libosmocore-dev (>= 1.11.0),
libosmo-netif-dev (>= 1.6.0),
libosmo-abis-dev (>= 2.0.0),
osmo-gsm-manuals-dev (>= 1.6.0)
Standards-Version: 3.9.8
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw

View File

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

View File

@@ -1,5 +1,9 @@
#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
@@ -8,14 +12,37 @@
#define PTYPE_UNDEFINED (-1)
struct mgcp_conn_rtp;
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;
};
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
const char *subtype_name, unsigned int match_nr);
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type);
struct mgcp_rtp_codecset {
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
/* array with assigned audio codecs to choose from (SDP) */
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
/* number of assigned audio codecs (SDP) */
unsigned int codecs_assigned;
};
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
const char *audio_name, const struct mgcp_codec_param *param);
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
const char *subtype_name, unsigned int match_nr);
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);

View File

@@ -31,6 +31,7 @@
#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...) \

View File

@@ -39,10 +39,11 @@ 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_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 struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
bool mgcp_check_param(const char *line);
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);

View File

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

View File

@@ -1,14 +1,73 @@
#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;
char *save;
struct mgcp_parse_hdr_pars hpars;
/* MGCP Body: */
struct mgcp_parse_sdp sdp;
};
/* Local connection options */
@@ -26,8 +85,6 @@ 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);

View File

@@ -0,0 +1,53 @@
#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
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn,
struct mgcp_parse_data *p);
struct mgcp_parse_data;
int mgcp_parse_sdp_data(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,9 +2,10 @@
#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, \
@@ -34,7 +35,7 @@ struct mgcp_trunk {
int keepalive_interval;
/* RTP patching */
int force_constant_ssrc; /* 0: don't, 1: once */
bool force_constant_ssrc;
int force_aligned_timing;
bool rfc5993_hr_convert;
@@ -78,6 +79,7 @@ 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

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

View File

@@ -40,6 +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 \
$(NULL)

View File

@@ -28,7 +28,7 @@
/* Helper function to dump codec information of a specified codec to a printable
* string, used by dump_codec_summary() */
static char *dump_codec(struct mgcp_rtp_codec *codec)
static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
{
static char str[256];
char *pt_str;
@@ -49,31 +49,25 @@ static char *dump_codec(struct mgcp_rtp_codec *codec)
}
/*! Dump a summary of all negotiated codecs to debug log
* \param[in] conn related rtp-connection. */
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
* \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)
{
struct mgcp_rtp_end *rtp;
unsigned int i;
struct mgcp_rtp_codec *codec;
struct mgcp_endpoint *endp;
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));
if (cset->codecs_assigned == 0) {
LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
return;
}
/* Store parsed codec information */
for (i = 0; i < rtp->codecs_assigned; i++) {
codec = &rtp->codecs[i];
for (i = 0; i < cset->codecs_assigned; i++) {
struct mgcp_rtp_codec *codec = &cset->codecs[i];
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
if (codec == rtp->codec)
if (codec == cset->codec)
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
LOGPC(DLMGCP, LOGL_DEBUG, "\n");
@@ -81,7 +75,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
}
/* Initalize or reset codec information with default data. */
static void codec_init(struct mgcp_rtp_codec *codec)
static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
{
*codec = (struct mgcp_rtp_codec){
.payload_type = -1,
@@ -94,20 +88,20 @@ static void codec_init(struct mgcp_rtp_codec *codec)
};
}
static void codec_free(struct mgcp_rtp_codec *codec)
static void mgcp_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_codec_reset_all(struct mgcp_conn_rtp *conn)
void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
{
int i;
for (i = 0; i < conn->end.codecs_assigned; i++)
codec_free(&conn->end.codecs[i]);
conn->end.codecs_assigned = 0;
conn->end.codec = NULL;
for (i = 0; i < cset->codecs_assigned; i++)
mgcp_codec_free(&cset->codecs[i]);
cset->codecs_assigned = 0;
cset->codec = NULL;
}
/*! Add codec configuration depending on payload type and/or codec name. This
@@ -118,23 +112,23 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
* \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)
int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
{
int rate;
int channels;
struct mgcp_rtp_codec *codec;
unsigned int pt_offset = conn->end.codecs_assigned;
unsigned int pt_offset = cset->codecs_assigned;
/* The amount of codecs we can store is limited, make sure we do not
* overrun this limit. */
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
if (cset->codecs_assigned >= MGCP_MAX_CODECS)
return -EINVAL;
/* First unused entry */
codec = &conn->end.codecs[conn->end.codecs_assigned];
codec = &cset->codecs[cset->codecs_assigned];
/* Initalize the codec struct with some default data to begin with */
codec_init(codec);
mgcp_codec_init(codec);
if (payload_type != PTYPE_UNDEFINED) {
/* Make sure we do not get any reserved or undefined type numbers */
@@ -268,11 +262,11 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
} else
codec->param_present = false;
conn->end.codecs_assigned++;
cset->codecs_assigned++;
return 0;
error:
/* Make sure we leave a clean codec entry on error. */
codec_free(codec);
mgcp_codec_free(codec);
return -EINVAL;
}
@@ -296,7 +290,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
}
/* Compare two codecs, all parameters must match up */
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const 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
@@ -325,7 +319,7 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
}
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const 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.
@@ -354,21 +348,18 @@ iufp:
return true;
}
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const 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 = rtp_end->codecs_assigned;
codecs_assigned = cset->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_same(codec, &rtp_end->codecs[i])) {
return &rtp_end->codecs[i];
if (codecs_same(codec, &cset->codecs[i])) {
return &cset->codecs[i];
break;
}
}
@@ -377,28 +368,26 @@ struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct m
}
/* For a given codec, find a convertible codec in the given connection. */
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
{
struct mgcp_rtp_end *rtp_end;
unsigned int i;
unsigned int codecs_assigned;
struct mgcp_rtp_codec *codec_convertible = NULL;
rtp_end = &conn->end;
/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
* the first run we will look for an exact match. */
codec_convertible = mgcp_codec_find_same(conn, codec);
codec_convertible = mgcp_codecset_find_same(cset, codec);
if (codec_convertible)
return codec_convertible;
/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
* payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
codecs_assigned = rtp_end->codecs_assigned;
codecs_assigned = cset->codecs_assigned;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (codecs_convertible(codec, &rtp_end->codecs[i])) {
codec_convertible = &rtp_end->codecs[i];
if (codecs_convertible(codec, &cset->codecs[i])) {
codec_convertible = &cset->codecs[i];
break;
}
}
@@ -408,20 +397,20 @@ static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn,
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
* a tentative decision is made.
* \param[inout] conn_src related rtp-connection.
* \param[inout] conn_dst related destination rtp-connection (NULL if not present).
* \param[in] cset_src related codec set.
* \param[inout] cset_dst related destination codec set (NULL if not present).
* \returns 0 on success, -EINVAL on failure. */
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
{
unsigned int i;
/* In case no destination connection is available (yet), or in case the destination connection exists but has
* no codecs assigned, we are forced to make a simple tentative decision:
* We just use the first codec of the source connection (conn_src) */
OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
if (conn_src->end.codecs_assigned >= 1) {
conn_src->end.codec = &conn_src->end.codecs[0];
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];
return 0;
} else
return -EINVAL;
@@ -430,38 +419,38 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn
/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
* of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
* required. */
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src);
if (codec_conn_dst) {
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) {
/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
* sides. We now set this codec on both connections. */
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
return 0;
}
}
/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
* to convert. */
for (i = 0; i < conn_src->end.codecs_assigned; i++) {
struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i];
struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src);
if (codec_conn_dst) {
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) {
/* We found the a codec that we can convert to. Set each side to its codec. */
conn_dst->end.codec = codec_conn_dst;
conn_src->end.codec = codec_conn_src;
cset_dst->codec = codec_cset_dst;
cset_src->codec = codec_cset_src;
return 0;
}
}
if (conn_dst->end.codecs_assigned)
conn_dst->end.codec = &conn_dst->end.codecs[0];
if (cset_dst->codecs_assigned)
cset_dst->codec = &cset_dst->codecs[0];
else
return -EINVAL;
if (conn_src->end.codecs_assigned)
conn_src->end.codec = &conn_src->end.codecs[0];
if (cset_src->codecs_assigned)
cset_src->codec = &cset_src->codecs[0];
else
return -EINVAL;
@@ -488,38 +477,36 @@ 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_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
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)
{
int i;
for (i = 0; i < conn->end.codecs_assigned; i++) {
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
for (i = 0; i < cset->codecs_assigned; i++) {
if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
if (match_nr) {
match_nr--;
continue;
}
return &conn->end.codecs[i];
return &cset->codecs[i];
}
}
return NULL;
}
/*! Lookup a codec that is assigned to a connection by its payload type number.
* \param[in] conn related rtp-connection.
* \param[in] cset related codec set.
* \param[in] payload_type number of the codec to look up.
* \returns pointer to codec struct on success, NULL on failure. */
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
{
struct mgcp_rtp_end *rtp_end = &conn->end;
unsigned int codecs_assigned = rtp_end->codecs_assigned;
struct mgcp_rtp_codec *codec = NULL;
size_t i;
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
for (i = 0; i < codecs_assigned; i++) {
if (payload_type == rtp_end->codecs[i].payload_type) {
codec = &rtp_end->codecs[i];
for (i = 0; i < cset->codecs_assigned; i++) {
if (payload_type == cset->codecs[i].payload_type) {
codec = &cset->codecs[i];
break;
}
}

View File

@@ -88,7 +88,6 @@ 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. */
@@ -106,17 +105,6 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
/* backpointer to the generic part of the connection */
conn->u.rtp.conn = conn;
end->rtp = NULL;
end->rtcp = NULL;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;
/* Set default values */
end->frames_per_packet = 0; /* unknown */
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = false;
end->maximum_packet_time = -1;
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
if (!conn_rtp->ctrg)
return -1;
@@ -124,9 +112,7 @@ 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);
/* Make sure codec table is reset */
mgcp_codec_reset_all(conn_rtp);
mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
return 0;
}
@@ -137,9 +123,8 @@ 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_free_port(&conn_rtp->end);
mgcp_rtp_end_cleanup(&conn_rtp->end);
rate_ctr_group_free(conn_rtp->ctrg);
mgcp_codec_reset_all(conn_rtp);
}
void mgcp_conn_watchdog_cb(void *data)

View File

@@ -56,133 +56,147 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
.sign_link = NULL,
};
/* EFR idle frame */
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1,
/* 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,
};
/* 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,
/* 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,
};
/* 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
@@ -660,7 +674,7 @@ void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
conn = mgcp_endp_get_conn_oldest(endp);
OSMO_ASSERT(conn);
conn_rtp = mgcp_conn_get_conn_rtp(conn);
codec = conn_rtp->end.codec;
codec = conn_rtp->end.cset.codec;
OSMO_ASSERT(codec);
/* Update codec information */

View File

@@ -264,6 +264,7 @@ 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));
@@ -275,7 +276,8 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
}
msgb_pull_to_l3(msg);
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
dst_codec = conn_rtp_dst->end.cset.codec;
if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
amr_hdr->cmr = 15; /* no change */
@@ -303,7 +305,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 = conn_rtp_dst->end.codec->payload_type,
.payload_type = dst_codec->payload_type,
.marker = 0,
.sequence = frame_nr,
.timestamp = 0,
@@ -502,7 +504,7 @@ 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->codec->rate));
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.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++;
@@ -550,7 +552,7 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
.extension = 0,
.padding = 0,
.version = 2,
.payload_type = conn_rtp_dst->end.codec->payload_type,
.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
.marker = 0,
.sequence = 0,
.timestamp = 0,
@@ -645,6 +647,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
struct rtp_hdr *rtph;
int rc = -1;
int iuup_length = 0;
struct mgcp_rtp_codec *src_codec;
int8_t rfci;
/* Tx RNL-DATA.req */
@@ -657,13 +660,14 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
/* TODO: CMR handling & multiple frames handling */
if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
src_codec = conn_src_rtp->end.cset.codec;
if (strcmp(src_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",
conn_src_rtp->end.codec->subtype_name);
src_codec->subtype_name);
goto free_ret;
}
if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
if (mgcp_codec_amr_is_octet_aligned(src_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,6 +23,7 @@
*/
#include <limits.h>
#include <ctype.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/osmux.h>
@@ -33,6 +34,10 @@
#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
@@ -122,8 +127,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
break;
case 2:
if (strcasecmp("MGCP", elem)) {
LOGP(DLMGCP, LOGL_ERROR,
"MGCP header parsing error\n");
LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
return -510;
}
break;
@@ -136,13 +140,87 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
}
if (i != 4) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
LOG_MGCP_PDATA(pdata, 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 */
@@ -153,19 +231,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 -1;
return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
}
if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
line);
return -2;
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
}
if (osmux_cid > OSMUX_CID_MAX) {
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
osmux_cid, OSMUX_CID_MAX);
return -2;
return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
}
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
@@ -173,20 +251,13 @@ 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 struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
bool mgcp_check_param(const char *line)
{
const size_t line_len = strlen(line);
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);
if (line[0] != '\0' && line_len < 2)
return false;
}
/* FIXME: A couple more checks wouldn't hurt... */

View File

@@ -332,7 +332,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->codec->rate * 20 / 1000;
tsdelta = rtp_end->cset.codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"Fixed packet duration and last timestamp delta "
"are not available, "
@@ -496,11 +496,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.codec) {
if (!conn_dst->end.cset.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.codec->payload_type;
rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type;
return 0;
}
@@ -523,7 +523,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
uint32_t timestamp, ssrc;
bool marker_bit;
struct rtp_hdr *rtp_hdr;
int payload = rtp_end->codec->payload_type;
struct mgcp_rtp_codec *codec = rtp_end->cset.codec;
int payload = codec->payload_type;
unsigned int len = msgb_length(msg);
if (len < sizeof(*rtp_hdr))
@@ -532,7 +533,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(rtp_end->codec->rate);
arrival_time = mgcp_get_current_ts(codec->rate);
ssrc = ntohl(rtp_hdr->ssrc);
marker_bit = !!rtp_hdr->marker;
transit = arrival_time - timestamp;
@@ -541,16 +542,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 = state->patch.orig_ssrc = ssrc;
state->in_stream.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",
@@ -560,7 +561,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 =
rtp_end->codec->rate * 20 / 1000;
codec->rate * 20 / 1000;
LOGPENDP(endp, DRTP, LOGL_NOTICE,
"fixed packet duration is not available, "
"using fixed 20ms instead: %d from %s:%d\n",
@@ -577,7 +578,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
osmo_sockaddr_port(&addr->u.sa));
state->in_stream.ssrc = ssrc;
if (rtp_end->force_constant_ssrc) {
if (state->patch.patch_ssrc) {
int16_t delta_seq;
/* Always increment seqno by 1 */
@@ -593,10 +594,7 @@ 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 "
@@ -816,8 +814,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
return;
hdr->version = 2;
hdr->payload_type = rtp_end->codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
hdr->payload_type = rtp_end->cset.codec->payload_type;
hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
hdr->ssrc = state->alt_rtp_tx_ssrc;
}
@@ -1183,6 +1181,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
struct mgcp_rtp_codec *src_codec;
struct mgcp_rtp_codec *dst_codec;
/* Make sure we have a valid RTP header, in cases where no RTP
* header is present, we will generate one. */
gen_rtp_header(msg, rtp_end, rtp_state);
@@ -1198,19 +1198,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
if (addr)
mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
src_codec = conn_src->end.cset.codec;
dst_codec = conn_dst->end.cset.codec;
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned);
} 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",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
msgb_free(msg);
return rc;
}
} else if (rtp_end->rfc5993_hr_convert &&
strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
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");
@@ -1434,7 +1436,7 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
}
/* Forward to E1 */
return mgcp_e1_send_rtp(conn->endp, conn_src->end.codec, msg);
return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg);
}
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1556,18 +1558,18 @@ static int rx_rtp(struct msgb *msg)
/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
if (mc->proto == MGCP_PROTO_RTP
&& conn_src->end.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
&& conn_src->end.cset.codec
&& mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) {
/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
* communicated via SDP when the connection was created/modfied. */
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
goto out_free;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa);
goto out_free;
}
}
@@ -1623,78 +1625,23 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr
return rc;
}
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
{
int rc, rtp_fd, rtcp_fd;
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
rc = mgcp_create_bind(source_addr, rtp_end->local_port, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTP port: %s:%d\n",
source_addr, rtp_end->local_port);
goto cleanup0;
}
rtp_fd = rc;
rc = mgcp_create_bind(source_addr, rtp_end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to create RTCP port: %s:%d\n",
source_addr, rtp_end->local_port + 1);
goto cleanup1;
}
rtcp_fd = rc;
if (osmo_iofd_register(rtp_end->rtp, rtp_fd) < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTP port %d\n",
rtp_end->local_port);
goto cleanup2;
}
if (osmo_iofd_register(rtp_end->rtcp, rtcp_fd) != 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"failed to register RTCP port %d\n",
rtp_end->local_port + 1);
goto cleanup3;
}
return 0;
cleanup3:
osmo_iofd_unregister(rtp_end->rtp);
cleanup2:
close(rtcp_fd);
cleanup1:
close(rtp_fd);
cleanup0:
return -1;
}
/*! bind RTP port to endpoint/connection.
* \param[in] endp endpoint that holds the RTP connection.
* \param[in] rtp_port port number to bind on.
* \param[in] conn associated RTP connection.
* \param[in] rtp_port port number to bind on.
* \returns 0 on success, -1 on ERROR. */
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn)
int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
{
char name[512];
struct mgcp_rtp_end *end;
struct mgcp_conn *conn = conn_rtp->conn;
struct mgcp_config *cfg = conn->endp->trunk->cfg;
struct mgcp_rtp_end *end = &conn_rtp->end;
int rc, rtp_fd, rtcp_fd;
snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id);
if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
(end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
rtp_port, mgcp_conn_dump(conn->conn));
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.
@@ -1704,43 +1651,55 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
}
end->local_port = rtp_port;
end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
if (!end->rtp)
return -EIO;
goto free_iofd_ret;
osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn);
if (!end->rtcp) {
osmo_iofd_free(end->rtp);
end->rtp = NULL;
return -EIO;
}
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 */
return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
}
/* NOTE: The port that is used for RTCP is the RTP port incremented by one
* (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
/***********************
* mgcp_rtp_end
**********************/
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;
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);
}
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;
/*! 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 (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 (end->rtcp) {
osmo_iofd_free(end->rtcp);
end->rtcp = NULL;
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;
}

View File

@@ -651,7 +651,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.codec->payload_type);
osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type);
osmux_xfrm_output_set_tx_cb(conn->osmux.out,
scheduled_from_osmux_tx_rtp_cb, conn);

View File

@@ -489,46 +489,6 @@ static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
return create_ok_response(rq->trunk, rq->endp, 200, "AUEP", rq->pdata->trans);
}
/* 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. */
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int i;
struct mgcp_port_range *range;
unsigned int tries;
OSMO_ASSERT(conn);
range = &endp->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_bind_net_rtp_port(endp, range->last_port, conn);
range->last_port += 2;
if (rc == 0) {
pthread_mutex_unlock(&range->lock);
return 0;
}
}
pthread_mutex_unlock(&range->lock);
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"Allocating a RTP/RTCP port failed %u times.\n",
tries);
return -1;
}
/*! Helper function for check_local_cx_options() to get a pointer of the next
* lco option identifier
* \param[in] lco string
@@ -722,106 +682,109 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
return 0;
}
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
struct mgcp_rtp_end *rtp)
{
struct mgcp_trunk *trunk = endp->trunk;
bool patch_ssrc = expect_ssrc_change && trunk->force_constant_ssrc;
rtp->force_aligned_timing = trunk->force_aligned_timing;
rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
rtp->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
"Configuring RTP endpoint: local port %d%s%s\n",
osmo_sockaddr_port(&rtp->addr.u.sa),
rtp->force_aligned_timing ? ", force constant timing" : "",
rtp->force_constant_ssrc ? ", force constant ssrc" : "");
}
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
const struct mgcp_rtp_end *rtp)
{
int f = 0;
struct mgcp_rtp_codec *codec = rtp->cset.codec;
/* Get the number of frames per channel and packet */
if (rtp->frames_per_packet)
f = rtp->frames_per_packet;
else if (rtp->packet_duration_ms && rtp->codec->frame_duration_num) {
int den = 1000 * rtp->codec->frame_duration_num;
f = (rtp->packet_duration_ms * rtp->codec->frame_duration_den +
else if (rtp->packet_duration_ms && codec->frame_duration_num) {
int den = 1000 * codec->frame_duration_num;
f = (rtp->packet_duration_ms * codec->frame_duration_den +
den / 2)
/ den;
}
return rtp->codec->rate * f * rtp->codec->frame_duration_num /
rtp->codec->frame_duration_den;
return codec->rate * f * codec->frame_duration_num /
codec->frame_duration_den;
}
/*! Initializes osmux socket if not yet initialized. Parses Osmux CID from MGCP line.
* \param[in] endp Endpoint willing to initialize osmux
* \param[in] line Line X-Osmux from MGCP header msg to parse
* \returns OSMUX CID, -1 for wildcard, -2 on parse error, -3 on osmux initalize error
*/
static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
static int mgcp_trunk_osmux_init_if_needed(struct mgcp_trunk *trunk)
{
if (!endp->trunk->cfg->osmux.initialized) {
if (osmux_init(endp->trunk) < 0) {
LOGPENDP(endp, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
return -3;
}
LOGPENDP(endp, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
if (trunk->cfg->osmux.initialized)
return 0;
if (osmux_init(trunk) < 0) {
LOGPTRUNK(trunk, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
return -3;
}
LOGPTRUNK(trunk, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
return 0;
}
/* Apply parsed SDP information stored in struct mgcp_parse_sdp to conn_rtp: */
static int handle_sdp(struct mgcp_conn_rtp *conn, struct mgcp_request_data *rq)
{
OSMO_ASSERT(conn);
OSMO_ASSERT(rq);
struct mgcp_parse_data *p = rq->pdata;
OSMO_ASSERT(p);
OSMO_ASSERT(p->hpars.have_sdp);
struct mgcp_parse_sdp *sdp = &p->sdp;
struct mgcp_rtp_end *rtp;
rtp = &conn->end;
if (sdp->ptime != MGCP_PARSE_SDP_PTIME_UNSET)
mgcp_rtp_end_set_packet_duration_ms(rtp, sdp->ptime);
if (sdp->maxptime != MGCP_PARSE_SDP_MAXPTIME_UNSET)
rtp->maximum_packet_time = sdp->maxptime;
if (sdp->rem_addr.u.sa.sa_family != AF_UNSPEC) {
/* Keep port, only apply ip address: */
uint16_t port = osmo_sockaddr_port(&rtp->addr.u.sa);
memcpy(&rtp->addr, &sdp->rem_addr, sizeof(rtp->addr));
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
}
return mgcp_parse_osmux_cid(line);
if (sdp->rtp_port != MGCP_PARSE_SDP_RTP_PORT_UNSET) {
osmo_sockaddr_set_port(&rtp->addr.u.sa, sdp->rtp_port);
rtp->rtcp_port = htons(sdp->rtp_port + 1);
}
/* Copy parsed codec set to conn: */
rtp->cset = sdp->cset;
return 0;
}
/* Process codec information contained in CRCX/MDCX */
static int handle_codec_info(struct mgcp_conn_rtp *conn,
struct mgcp_request_data *rq, int have_sdp, bool crcx)
static int handle_codec_info(struct mgcp_conn_rtp *conn, struct mgcp_request_data *rq)
{
struct mgcp_endpoint *endp = rq->endp;
struct mgcp_conn *conn_dst;
struct mgcp_conn_rtp *conn_dst_rtp;
struct mgcp_rtp_codecset *cset = &conn->end.cset;
int rc;
char *cmd;
if (crcx)
cmd = "CRCX";
else
cmd = "MDCX";
/* Collect codec information */
if (have_sdp) {
if (rq->pdata->hpars.have_sdp) {
/* If we have SDP, we ignore the local connection options and
* use only the SDP information. */
mgcp_codec_reset_all(conn);
rc = mgcp_parse_sdp_data(endp, conn, rq->pdata);
if (rc != 0) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"%s: sdp not parseable\n", cmd);
/* See also RFC 3661: Protocol error */
return 510;
}
rc = handle_sdp(conn, rq);
if (rc != 0)
goto error;
} else if (endp->local_options.codec) {
/* When no SDP is available, we use the codec information from
* the local connection options (if present) */
mgcp_codec_reset_all(conn);
rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec, NULL);
mgcp_codecset_reset(cset);
rc = mgcp_codecset_add_codec(cset, PTYPE_UNDEFINED, endp->local_options.codec, NULL);
if (rc != 0)
goto error;
}
/* Make sure we always set a sane default codec */
if (conn->end.codecs_assigned == 0) {
if (cset->codecs_assigned == 0) {
/* When SDP and/or LCO did not supply any codec information,
* than it makes sense to pick a sane default: (payload-type 0,
* PCMU), see also: OS#2658 */
mgcp_codec_reset_all(conn);
rc = mgcp_codec_add(conn, 0, NULL, NULL);
mgcp_codecset_reset(cset);
rc = mgcp_codecset_add_codec(cset, 0, NULL, NULL);
if (rc != 0)
goto error;
}
@@ -834,55 +797,27 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
conn_dst_rtp = NULL;
/* Make codec decision */
if (mgcp_codec_decide(conn, conn_dst_rtp) != 0)
if (mgcp_codecset_decide(&conn->end.cset, conn_dst_rtp ? &conn_dst_rtp->end.cset : NULL) != 0)
goto error;
return 0;
error:
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"%s: codec negotiation failure\n", cmd);
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "%s: codec negotiation failure\n", rq->name);
/* See also RFC 3661: Codec negotiation failure */
return 534;
}
static bool parse_x_osmo_ign(struct mgcp_endpoint *endp, 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"))
endp->x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
else
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
}
return true;
}
/* CRCX command handler, processes the received command */
static struct msgb *handle_create_con(struct mgcp_request_data *rq)
{
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct mgcp_parse_hdr_pars *hpars = &pdata->hpars;
struct rate_ctr_group *rate_ctrs;
int error_code = 400;
const char *local_options = NULL;
const char *callid = NULL;
enum mgcp_connection_mode mode = MGCP_CONN_NONE;
char *line;
int have_sdp = 0, remote_osmux_cid = -2;
int remote_osmux_cid;
struct mgcp_conn *conn = NULL;
struct mgcp_conn_rtp *conn_rtp = NULL;
char conn_name[512];
@@ -913,69 +848,59 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
}
/* parse CallID C: and LocalParameters L: */
for_each_line(line, pdata->save) {
if (!mgcp_check_param(endp, trunk, line))
continue;
switch (toupper(line[0])) {
case 'L':
local_options = (const char *)line + 3;
break;
case 'C':
callid = (const char *)line + 3;
break;
case 'I':
/* It is illegal to send a connection identifier
* together with a CRCX, the MGW will assign the
* connection identifier by itself on CRCX */
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BAD_ACTION));
return create_err_response(rq->trunk, NULL, 523, "CRCX", pdata->trans);
break;
case 'M':
mode = mgcp_parse_conn_mode((const char *)line + 3);
break;
case 'X':
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
/* If osmux is disabled, just skip setting it up */
if (rq->endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
break;
remote_osmux_cid = mgcp_osmux_setup(endp, line);
break;
}
if (parse_x_osmo_ign(endp, line))
break;
/* Ignore unknown X-headers */
break;
case '\0':
have_sdp = 1;
goto mgcp_header_done;
default:
LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
"CRCX: unhandled option: '%c'/%d\n", *line, *line);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "CRCX", pdata->trans);
break;
}
rc = mgcp_parse_hdr_pars(pdata);
switch (rc) {
case 0:
break; /* all good, continue below */
case -539:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, -rc, "CRCX", pdata->trans);
default:
return create_err_response(rq->trunk, NULL, -rc, "CRCX", pdata->trans);
}
mgcp_header_done:
/* Check parameters */
if (!callid) {
if (!hpars->callid) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"CRCX: insufficient parameters, missing callid\n");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_MISSING_CALLID));
return create_err_response(endp, endp, 516, "CRCX", pdata->trans);
}
if (mode == MGCP_CONN_NONE) {
if (hpars->mode == MGCP_CONN_NONE) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"CRCX: insufficient parameters, invalid mode\n");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
return create_err_response(endp, endp, 517, "CRCX", pdata->trans);
}
/* It is illegal to send a connection identifier
* together with a CRCX, the MGW will assign the
* connection identifier by itself on CRCX */
if (hpars->connid) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "CRCX: 'I: %s' not expected!\n", hpars->connid);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BAD_ACTION));
return create_err_response(endp, endp, 523, "CRCX", pdata->trans);
}
/* Parse SDP if found: */
if (hpars->have_sdp) {
rc = mgcp_parse_sdp_data(pdata);
if (rc < 0) { /* See also RFC 3661: Protocol error */
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "CRCX: sdp not parseable\n");
return create_err_response(endp, endp, 510, "CRCX", pdata->trans);
}
}
remote_osmux_cid = hpars->remote_osmux_cid;
/* If osmux is disabled, just skip setting it up */
if (trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
/* Make sure osmux is setup: */
if (remote_osmux_cid != MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET)
mgcp_trunk_osmux_init_if_needed(trunk);
/* Check if we are able to accept the creation of another connection */
if (mgcp_endp_is_full(endp)) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
@@ -995,9 +920,12 @@ mgcp_header_done:
}
}
/* Update endp->x_osmo_ign: */
endp->x_osmo_ign |= hpars->x_osmo_ign;
/* Check if this endpoint already serves a call, if so, check if the
* callids match up so that we are sure that this is our call */
if (endp->callid && mgcp_verify_call_id(endp, callid)) {
if (endp->callid && mgcp_verify_call_id(endp, hpars->callid)) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"CRCX: already seized by other call (%s)\n",
endp->callid);
@@ -1017,14 +945,14 @@ mgcp_header_done:
/* Claim endpoint resources. This will also set the callid,
* creating additional connections will only be possible if
* the callid matches up (see above). */
rc = mgcp_endp_claim(endp, callid);
rc = mgcp_endp_claim(endp, hpars->callid);
if (rc != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CLAIM));
return create_err_response(endp, endp, 502, "CRCX", pdata->trans);
}
}
snprintf(conn_name, sizeof(conn_name), "%s", callid);
snprintf(conn_name, sizeof(conn_name), "%s", hpars->callid);
conn = mgcp_conn_alloc(trunk->endpoints, endp, MGCP_CONN_TYPE_RTP, conn_name);
if (!conn) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
@@ -1033,7 +961,7 @@ mgcp_header_done:
goto error2;
}
if (mgcp_conn_set_mode(conn, mode) < 0) {
if (mgcp_conn_set_mode(conn, hpars->mode) < 0) {
error_code = 517;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
goto error2;
@@ -1060,9 +988,9 @@ mgcp_header_done:
}
/* Set local connection options, if present */
if (local_options) {
if (hpars->local_options) {
rc = set_local_cx_options(trunk->endpoints,
&endp->local_options, local_options);
&endp->local_options, hpars->local_options);
if (rc != 0) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"CRCX: invalid local connection options!\n");
@@ -1073,8 +1001,8 @@ mgcp_header_done:
}
/* Handle codec information and decide for a suitable codec */
rc = handle_codec_info(conn_rtp, rq, have_sdp, true);
mgcp_codec_summary(conn_rtp);
rc = handle_codec_info(conn_rtp, rq);
mgcp_codecset_summary(&conn_rtp->end.cset, mgcp_conn_dump(conn));
if (rc) {
error_code = rc;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
@@ -1082,24 +1010,18 @@ mgcp_header_done:
}
/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
/* TODO: "codec" probably needs to be moved from endp to conn */
if (conn_rtp->type == MGCP_RTP_DEFAULT && strcmp(conn_rtp->end.codec->subtype_name, "VND.3GPP.IUFP") == 0) {
if (conn_rtp->type == MGCP_RTP_DEFAULT &&
strcmp(conn_rtp->end.cset.codec->subtype_name, "VND.3GPP.IUFP") == 0) {
rc = mgcp_conn_iuup_init(conn_rtp);
}
if (pdata->cfg->force_ptime) {
conn_rtp->end.packet_duration_ms = pdata->cfg->force_ptime;
conn_rtp->end.force_output_ptime = 1;
}
mgcp_rtp_end_config(endp, 0, &conn_rtp->end);
/* Find a local address for conn based on policy and initial SDP remote
information, then find a free port for it */
if (mgcp_get_local_addr(conn_rtp->end.local_addr, conn_rtp) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
}
if (allocate_port(endp, conn_rtp) != 0) {
if (mgcp_trunk_allocate_conn_rtp_ports(trunk, conn_rtp) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
}
@@ -1149,17 +1071,12 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct mgcp_parse_hdr_pars *hpars = &pdata->hpars;
struct rate_ctr_group *rate_ctrs;
char new_local_addr[INET6_ADDRSTRLEN];
int error_code = 500;
int have_sdp = 0;
char *line;
const char *local_options = NULL;
enum mgcp_connection_mode mode = MGCP_CONN_NONE;
struct mgcp_conn *conn = NULL;
struct mgcp_conn_rtp *conn_rtp = NULL;
const char *conn_id = NULL;
int remote_osmux_cid = -2;
int rc;
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
@@ -1192,64 +1109,43 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
}
for_each_line(line, pdata->save) {
if (!mgcp_check_param(endp, trunk, line))
continue;
switch (toupper(line[0])) {
case 'C':
if (mgcp_verify_call_id(endp, line + 3) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CALLID));
error_code = 516;
goto error3;
}
break;
case 'I':
conn_id = (const char *)line + 3;
if ((error_code = mgcp_verify_ci(endp, conn_id))) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CONNID));
goto error3;
}
break;
case 'L':
local_options = (const char *)line + 3;
break;
case 'M':
mode = mgcp_parse_conn_mode((const char *)line + 3);
break;
case 'X':
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
/* If osmux is disabled, just skip setting it up */
if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
break;
remote_osmux_cid = mgcp_osmux_setup(endp, line);
break;
}
/* Ignore unknown X-headers */
break;
case '\0':
have_sdp = 1;
goto mgcp_header_done;
break;
default:
LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
"MDCX: Unhandled MGCP option: '%c'/%d\n",
line[0], line[0]);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "MDCX", pdata->trans);
break;
}
rc = mgcp_parse_hdr_pars(pdata);
switch (rc) {
case 0:
break; /* all good, continue below */
case -539:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, -rc, "MDCX", pdata->trans);
default:
return create_err_response(rq->trunk, NULL, -rc, "MDCX", pdata->trans);
}
mgcp_header_done:
if (!conn_id) {
if (hpars->callid && mgcp_verify_call_id(endp, hpars->callid) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CALLID));
return create_err_response(endp, endp, 516, "MDCX", pdata->trans);
}
if (!hpars->connid) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"MDCX: insufficient parameters, missing ci (connectionIdentifier)\n");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONNID));
return create_err_response(endp, endp, 515, "MDCX", pdata->trans);
} else if ((error_code = mgcp_verify_ci(endp, hpars->connid)) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CONNID));
return create_err_response(endp, endp, error_code, "MDCX", pdata->trans);
}
conn = mgcp_endp_get_conn(endp, conn_id);
/* Parse SDP if found: */
if (hpars->have_sdp) {
rc = mgcp_parse_sdp_data(pdata);
if (rc < 0) {
/* See also RFC 3661: Protocol error */
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "MDCX: sdp not parseable\n");
return create_err_response(endp, endp, 510, "MDCX", pdata->trans);
}
}
conn = mgcp_endp_get_conn(endp, hpars->connid);
if (!conn) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_CONN_NOT_FOUND));
return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
@@ -1257,20 +1153,18 @@ mgcp_header_done:
mgcp_conn_watchdog_kick(conn);
if (mode != MGCP_CONN_NONE) {
if (mgcp_conn_set_mode(conn, mode) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_MODE));
error_code = 517;
goto error3;
}
} else {
if (hpars->mode == MGCP_CONN_NONE) {
/* Reset conn mode in case it was tweaked through VTY: */
conn->mode = conn->mode_orig;
} else if (mgcp_conn_set_mode(conn, hpars->mode) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_MODE));
return create_err_response(endp, endp, 517, "MDCX", pdata->trans);
}
/* Set local connection options, if present */
if (local_options) {
if (hpars->local_options) {
rc = set_local_cx_options(trunk->endpoints,
&endp->local_options, local_options);
&endp->local_options, hpars->local_options);
if (rc != 0) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"MDCX: invalid local connection options!\n");
@@ -1284,40 +1178,37 @@ mgcp_header_done:
OSMO_ASSERT(conn_rtp);
/* Handle codec information and decide for a suitable codec */
rc = handle_codec_info(conn_rtp, rq, have_sdp, false);
mgcp_codec_summary(conn_rtp);
rc = handle_codec_info(conn_rtp, rq);
mgcp_codecset_summary(&conn_rtp->end.cset, mgcp_conn_dump(conn));
if (rc) {
error_code = rc;
goto error3;
}
/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
/* TODO: "codec" probably needs to be moved from endp to conn */
if (conn_rtp->type == MGCP_RTP_DEFAULT && strcmp(conn_rtp->end.codec->subtype_name, "VND.3GPP.IUFP") == 0)
if (conn_rtp->type == MGCP_RTP_DEFAULT &&
strcmp(conn_rtp->end.cset.codec->subtype_name, "VND.3GPP.IUFP") == 0)
rc = mgcp_conn_iuup_init(conn_rtp);
if (mgcp_conn_rtp_is_osmux(conn_rtp)) {
OSMO_ASSERT(conn_rtp->osmux.local_cid_allocated);
if (remote_osmux_cid < -1) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"MDCX: Failed to parse Osmux CID!\n");
if (hpars->remote_osmux_cid < -1) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "MDCX: Failed to parse Osmux CID!\n");
goto error3;
} else if (remote_osmux_cid == -1) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"MDCX: wilcard in MDCX is not supported!\n");
}
if (hpars->remote_osmux_cid == -1) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "MDCX: wilcard in MDCX is not supported!\n");
goto error3;
} else if (conn_rtp->osmux.remote_cid_present &&
remote_osmux_cid != conn_rtp->osmux.remote_cid) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"MDCX: changing already allocated CID is not supported!\n");
}
if (conn_rtp->osmux.remote_cid_present &&
hpars->remote_osmux_cid != conn_rtp->osmux.remote_cid) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "MDCX: changing already allocated CID is not supported!\n");
goto error3;
}
conn_rtp->osmux.remote_cid_present = true;
conn_rtp->osmux.remote_cid = hpars->remote_osmux_cid;
if (conn_osmux_event_rx_crcx_mdcx(conn_rtp) < 0) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "MDCX: Osmux handling failed!\n");
goto error3;
} else {
conn_rtp->osmux.remote_cid_present = true;
conn_rtp->osmux.remote_cid = remote_osmux_cid;
if (conn_osmux_event_rx_crcx_mdcx(conn_rtp) < 0) {
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
"MDCX: Osmux handling failed!\n");
goto error3;
}
}
}
@@ -1332,7 +1223,7 @@ mgcp_header_done:
if (strcmp(new_local_addr, conn_rtp->end.local_addr)) {
osmo_strlcpy(conn_rtp->end.local_addr, new_local_addr, sizeof(conn_rtp->end.local_addr));
mgcp_rtp_end_free_port(&conn_rtp->end);
if (allocate_port(endp, conn_rtp) != 0) {
if (mgcp_trunk_allocate_conn_rtp_ports(trunk, conn_rtp) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error3;
}
@@ -1343,8 +1234,6 @@ mgcp_header_done:
goto error3;
}
mgcp_rtp_end_config(endp, 1, &conn_rtp->end);
/* modify */
LOGPCONN(conn, DLMGCP, LOGL_DEBUG,
"MDCX: modified conn:%s\n", mgcp_conn_dump(conn));
@@ -1371,13 +1260,12 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
struct mgcp_parse_data *pdata = rq->pdata;
struct mgcp_trunk *trunk = rq->trunk;
struct mgcp_endpoint *endp = rq->endp;
struct mgcp_parse_hdr_pars *hpars = &pdata->hpars;
struct rate_ctr_group *rate_ctrs;
int error_code = 400;
char *line;
char stats[1048];
const char *conn_id = NULL;
struct mgcp_conn *conn = NULL;
unsigned int i;
int rc;
/* NOTE: In this handler we can not take it for granted that the endp
* pointer will be populated, however a trunk is always guaranteed (except for 'null' endp).
@@ -1419,49 +1307,42 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
return create_ok_response(trunk, NULL, 200, "DLCX", pdata->trans);
}
for_each_line(line, pdata->save) {
if (!mgcp_check_param(endp, trunk, line))
continue;
rc = mgcp_parse_hdr_pars(pdata);
switch (rc) {
case 0:
break; /* all good, continue below */
case -539:
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, -rc, "DLCX", pdata->trans);
default:
return create_err_response(rq->trunk, NULL, -rc, "DLCX", pdata->trans);
}
switch (toupper(line[0])) {
case 'C':
/* If we have no endpoint, but a call id in the request,
then this request cannot be handled */
if (!endp) {
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
"cannot handle requests with call-id (C) without endpoint -- abort!");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
}
if (mgcp_verify_call_id(endp, line + 3) != 0) {
error_code = 516;
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CALLID));
goto error3;
}
break;
case 'I':
/* If we have no endpoint, but a connection id in the request,
then this request cannot be handled */
if (!endp) {
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
"cannot handle requests with conn-id (I) without endpoint -- abort!");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
}
conn_id = (const char *)line + 3;
if ((error_code = mgcp_verify_ci(endp, conn_id))) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CONNID));
goto error3;
}
break;
default:
LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: Unhandled MGCP option: '%c'/%d\n",
line[0], line[0]);
if (hpars->callid) {
/* If we have no endpoint, but a call id in the request, then this request cannot be handled */
if (!endp) {
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
"cannot handle requests with call-id (C) without endpoint -- abort!");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
break;
}
if (mgcp_verify_call_id(endp, hpars->callid) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CALLID));
return create_err_response(endp, endp, 516, "DLCX", pdata->trans);
}
}
if (hpars->connid) {
/* If we have no endpoint, but a connection id in the request, then this request cannot be handled */
if (!endp) {
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
"cannot handle requests with conn-id (I) without endpoint -- abort!");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
}
if ((rc = mgcp_verify_ci(endp, hpars->connid)) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CONNID));
return create_err_response(endp, endp, rc, "DLCX", pdata->trans);
}
}
@@ -1473,7 +1354,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
* wildcarded DLCX that refers to the selected endpoint. This means
* that we drop all connections on that specific endpoint at once.
* (See also RFC3435 Section F.7) */
if (!conn_id) {
if (!hpars->connid) {
int num_conns = mgcp_endp_num_conns(endp);
LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
"DLCX: missing ci (connectionIdentifier), will remove all connections (%d total) at once\n",
@@ -1491,10 +1372,10 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
}
/* Find the connection */
conn = mgcp_endp_get_conn(endp, conn_id);
conn = mgcp_endp_get_conn(endp, hpars->connid);
if (!conn) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CONNID));
goto error3;
return create_err_response(endp, endp, 400, "DLCX", pdata->trans);
}
/* save the statistics of the current connection */
mgcp_format_stats(stats, sizeof(stats), conn);
@@ -1515,9 +1396,6 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS));
return create_ok_resp_with_param(endp, endp, 250, "DLCX", pdata->trans, stats);
error3:
return create_err_response(endp, endp, error_code, "DLCX", pdata->trans);
}
/* RSIP command handler, processes the received command */

View File

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

View File

@@ -312,16 +312,13 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
}
/*! Analyze SDP input string.
* \param[in] endp trunk endpoint.
* \param[out] conn associated rtp connection.
* \param[out] caller provided memory to store the parsing results.
* \param[inout] p 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(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
int mgcp_parse_sdp_data(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];
@@ -331,19 +328,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
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]) {
@@ -361,19 +353,19 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
if (ptime2 > 0 && ptime2 != ptime)
rtp->packet_duration_ms = 0;
sdp->ptime = 0;
else
rtp->packet_duration_ms = ptime;
sdp->ptime = ptime;
break;
}
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
rtp->maximum_packet_time = ptime2;
sdp->maxptime = ptime2;
break;
}
if (strncmp("a=fmtp:", line, 6) == 0) {
rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
if (rc >= 0)
fmtp_used++;
break;
@@ -382,33 +374,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
break;
case 'm':
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
if (rc == 1) {
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
rtp->rtcp_port = htons(port + 1);
}
if (rc == 1)
sdp->rtp_port = port;
rc = pt_from_sdp(conn->conn, codecs,
ARRAY_SIZE(codecs), line);
rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
if (rc > 0)
codecs_used = rc;
break;
case 'c':
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
talloc_free(tmp_ctx);
return -1;
}
break;
default:
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]);
LOGP(DLMGCP, LOGL_NOTICE,
"Unhandled SDP option: '%c'/%d on %s\n",
line[0], line[0], p->epname);
break;
}
}
@@ -422,23 +404,22 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
/* 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_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
if (rc < 0)
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
}
talloc_free(tmp_ctx);
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);
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);
if (codecs_used == 0)
LOGPC(DLMGCP, LOGL_NOTICE, "none");
for (i = 0; i < codecs_used; i++) {
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
rtp->codecs[i].payload_type,
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
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, "\n");
@@ -542,7 +523,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
OSMO_ASSERT(sdp);
OSMO_ASSERT(addr);
codec = conn->end.codec;
codec = conn->end.cset.codec;
audio_name = codec->audio_name;
payload_type = codec->payload_type;

View File

@@ -306,3 +306,43 @@ 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->codec;
struct mgcp_rtp_codec *codec = end->cset.codec;
struct rate_ctr *tx_packets, *tx_bytes;
struct rate_ctr *rx_packets, *rx_bytes;
struct rate_ctr *dropped_packets;
@@ -857,7 +857,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 = 1;
trunk->force_constant_ssrc = true;
return CMD_SUCCESS;
}
@@ -868,7 +868,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 = 0;
trunk->force_constant_ssrc = false;
return CMD_SUCCESS;
}
@@ -923,7 +923,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 = 0;
trunk->force_constant_ssrc = false;
trunk->force_aligned_timing = 0;
trunk->rfc5993_hr_convert = false;
return CMD_SUCCESS;
@@ -1197,7 +1197,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 = 1;
trunk->force_constant_ssrc = true;
return CMD_SUCCESS;
}
@@ -1207,7 +1207,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 = 0;
trunk->force_constant_ssrc = false;
return CMD_SUCCESS;
}
@@ -1257,7 +1257,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 = 0;
trunk->force_constant_ssrc = false;
trunk->force_aligned_timing = 0;
trunk->rfc5993_hr_convert = false;
return CMD_SUCCESS;
@@ -1361,7 +1361,7 @@ DEFUN(loop_conn,
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);
mgcp_rtp_end_config(endp, 1, &conn_rtp->end);
conn_rtp->state.patch.patch_ssrc = true;
} else {
/* FIXME: Introduce support for other connection (E1)
* types when implementation is available */

View File

@@ -1023,14 +1023,14 @@ static void test_messages(void)
fprintf(stderr, "endpoint:%s: "
"payload type %d (expected %d)\n",
last_endpoint,
conn->end.codec->payload_type, t->ptype);
conn->end.cset.codec->payload_type, t->ptype);
if (t->ptype != PTYPE_IGNORE)
OSMO_ASSERT(conn->end.codec->payload_type ==
OSMO_ASSERT(conn->end.cset.codec->payload_type ==
t->ptype);
/* Reset them again for next test */
conn->end.codec->payload_type = PTYPE_NONE;
conn->end.cset.codec->payload_type = PTYPE_NONE;
}
}
@@ -1466,8 +1466,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
rtp = &conn->end;
OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->codec = &rtp->codecs[0];
OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
rtp->cset.codec = &rtp->cset.codecs[0];
for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
struct rtp_packet_info *info = test_rtp_packets1 + i;
@@ -1479,7 +1479,6 @@ 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);
@@ -1550,7 +1549,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
/* Allocate 2@mgw with three codecs, last one ignored */
last_endpoint[0] = '\0';
@@ -1566,7 +1565,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
OSMO_ASSERT(conn->end.cset.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
@@ -1587,7 +1586,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
/* Allocate 4@mgw with a single codec */
last_endpoint[0] = '\0';
@@ -1603,7 +1602,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 18);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
last_endpoint[0] = '\0';
@@ -1619,7 +1618,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
inp = create_msg(MDCX_NAT_DUMMY, conn_id);
last_endpoint[0] = '\0';
@@ -1631,7 +1630,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 3);
OSMO_ASSERT(conn->end.cset.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);
@@ -1662,7 +1661,7 @@ static void test_multilple_codec(void)
OSMO_ASSERT(endp);
conn = mgcp_endp_get_conn_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 0);
OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
mgcp_endpoints_release(trunk);
talloc_free(cfg);
@@ -2195,7 +2194,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_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
if (expect->payload_type_map[index_conn_src] == -EINVAL
&& expect->payload_type_map[index_conn_dst] == -EINVAL)
printf(" codec decision failed (expected)!\n");
@@ -2205,19 +2204,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.codec) {
payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
if (conn[index_conn_src].end.cset.codec) {
payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src);
} else {
payload_type_conn_src = -EINVAL;
printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
}
if (conn[index_conn_dst].end.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
if (conn[index_conn_dst].end.cset.codec) {
payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
printf(" conn[%u]: codec:%s, pt:%d\n",
index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name,
payload_type_conn_dst);
} else {
payload_type_conn_dst = -EINVAL;
@@ -2265,8 +2264,8 @@ static void test_mgcp_codec_decide(void)
if (!codec->audio_name)
break;
rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
codec->param);
rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, 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 ?