mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 13:03:33 +00:00
Compare commits
19 Commits
neels/sdp2
...
1.14.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2eacae8f2e | ||
|
|
403d5f1489 | ||
|
|
f227633959 | ||
|
|
83c8846728 | ||
|
|
78ee99adcf | ||
|
|
de4090d920 | ||
|
|
732cadd2c8 | ||
|
|
6747b60a95 | ||
|
|
90ae9ed0a2 | ||
|
|
206be49c69 | ||
|
|
45559e9230 | ||
|
|
f94b846224 | ||
|
|
3ea3a69821 | ||
|
|
46ddc65626 | ||
|
|
71f313749e | ||
|
|
80a5abbbe3 | ||
|
|
ba812f7e86 | ||
|
|
345c37a543 | ||
|
|
b3457cd250 |
14
configure.ac
14
configure.ac
@@ -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
49
debian/changelog
vendored
@@ -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
6
debian/control
vendored
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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...) \
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
53
include/osmocom/mgcp/mgcp_rtp_end.h
Normal file
53
include/osmocom/mgcp/mgcp_rtp_end.h
Normal 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);
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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... */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
104
src/libosmo-mgcp/mgcp_rtp_end.c
Normal file
104
src/libosmo-mgcp/mgcp_rtp_end.c
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 ?
|
||||
|
||||
Reference in New Issue
Block a user