summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--TODO-RELEASE2
-rw-r--r--configure.ac41
-rwxr-xr-xcontrib/jenkins.sh2
-rw-r--r--contrib/systemd/osmo-mgw.service11
-rw-r--r--doc/examples/osmo-mgw/osmo-mgw.cfg23
-rw-r--r--include/Makefile.am1
-rw-r--r--include/osmocom/legacy_mgcp/vty.h25
-rw-r--r--include/osmocom/mgcp/Makefile.am2
-rw-r--r--include/osmocom/mgcp/mgcp.h8
-rw-r--r--include/osmocom/mgcp/mgcp_common.h14
-rw-r--r--include/osmocom/mgcp/mgcp_conn.h9
-rw-r--r--include/osmocom/mgcp/mgcp_endp.h99
-rw-r--r--include/osmocom/mgcp/mgcp_ep.h50
-rw-r--r--include/osmocom/mgcp/mgcp_internal.h89
-rw-r--r--include/osmocom/mgcp/mgcp_msg.h4
-rw-r--r--include/osmocom/mgcp/vty.h25
-rw-r--r--include/osmocom/mgcp_client/mgcp_client.h19
-rw-r--r--include/osmocom/mgcp_client/mgcp_client_fsm.h33
-rw-r--r--libosmo-mgcp.pc.in10
-rw-r--r--src/libosmo-legacy-mgcp/Makefile.am2
-rw-r--r--src/libosmo-legacy-mgcp/mgcp_protocol.c42
-rw-r--r--src/libosmo-mgcp-client/Makefile.am3
-rw-r--r--src/libosmo-mgcp-client/mgcp_client.c410
-rw-r--r--src/libosmo-mgcp-client/mgcp_client_fsm.c669
-rw-r--r--src/libosmo-mgcp-client/mgcp_client_vty.c11
-rw-r--r--src/libosmo-mgcp/Makefile.am16
-rw-r--r--src/libosmo-mgcp/mgcp_conn.c141
-rw-r--r--src/libosmo-mgcp/mgcp_endp.c (renamed from src/libosmo-mgcp/mgcp_ep.c)28
-rw-r--r--src/libosmo-mgcp/mgcp_msg.c173
-rw-r--r--src/libosmo-mgcp/mgcp_network.c255
-rw-r--r--src/libosmo-mgcp/mgcp_osmux.c26
-rw-r--r--src/libosmo-mgcp/mgcp_protocol.c372
-rw-r--r--src/libosmo-mgcp/mgcp_sdp.c3
-rw-r--r--src/libosmo-mgcp/mgcp_stat.c51
-rw-r--r--src/libosmo-mgcp/mgcp_vty.c92
-rw-r--r--src/osmo-bsc_mgcp/Makefile.am2
-rw-r--r--src/osmo-bsc_mgcp/mgcp_main.c54
-rw-r--r--src/osmo-mgw/Makefile.am6
-rw-r--r--src/osmo-mgw/mgw_main.c138
-rw-r--r--tests/legacy_mgcp/mgcp_test.c12
-rw-r--r--tests/legacy_mgcp/mgcp_transcoding_test.c3
-rw-r--r--tests/mgcp/Makefile.am5
-rw-r--r--tests/mgcp/mgcp_test.c408
-rw-r--r--tests/mgcp/mgcp_test.ok702
-rw-r--r--tests/mgcp_client/Makefile.am3
-rw-r--r--tests/mgcp_client/mgcp_client_test.c169
-rw-r--r--tests/mgcp_client/mgcp_client_test.err63
-rw-r--r--tests/mgcp_client/mgcp_client_test.ok43
49 files changed, 3314 insertions, 1056 deletions
diff --git a/Makefile.am b/Makefile.am
index 7b9ef95..8fb6e6c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,6 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
libosmo-legacy-mgcp.pc \
libosmo-mgcp-client.pc \
- libosmo-mgcp.pc \
$(NULL)
BUILT_SOURCES = $(top_srcdir)/.version
diff --git a/TODO-RELEASE b/TODO-RELEASE
index d198b97..c5a3b36 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -23,4 +23,4 @@
# If any interfaces have been added since the last public release, a++;
# If any interfaces have been removed or changed since the last public release, a=0.
#
-#library what description / commit summary line
+#library what description / commit summary line
diff --git a/configure.ac b/configure.ac
index dea41b1..0ded288 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,9 +39,40 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.10.0)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
-PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.1.0)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
+PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.2.0)
+
+AC_ARG_ENABLE(sanitize,
+ [AS_HELP_STRING(
+ [--enable-sanitize],
+ [Compile with address sanitizer enabled],
+ )],
+ [sanitize=$enableval], [sanitize="no"])
+if test x"$sanitize" = x"yes"
+then
+ CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
+ CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
+fi
+
+AC_ARG_ENABLE(werror,
+ [AS_HELP_STRING(
+ [--enable-werror],
+ [Turn all compiler warnings into errors, with exceptions:
+ a) deprecation (allow upstream to mark deprecation without breaking builds);
+ b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
+ ]
+ )],
+ [werror=$enableval], [werror="no"])
+if test x"$werror" = x"yes"
+then
+ WERROR_FLAGS="-Werror"
+ WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
+ WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
+ CFLAGS="$CFLAGS $WERROR_FLAGS"
+ CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
+fi
# Enable/disable transcoding within osmo-bsc_mgcp?
AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])],
@@ -113,13 +144,15 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
AC_MSG_RESULT([$enable_ext_tests])
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
+AC_MSG_RESULT([CFLAGS="$CFLAGS"])
+AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
+
dnl Generate the output
AM_CONFIG_HEADER(bscconfig.h)
AC_OUTPUT(
libosmo-legacy-mgcp.pc
libosmo-mgcp-client.pc
- libosmo-mgcp.pc
include/Makefile
include/osmocom/Makefile
include/osmocom/legacy_mgcp/Makefile
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh
index 44152dc..222bd8f 100755
--- a/contrib/jenkins.sh
+++ b/contrib/jenkins.sh
@@ -37,7 +37,7 @@ set -x
cd "$base"
autoreconf --install --force
-./configure $MGCP --enable-vty-tests --enable-external-tests
+./configure $MGCP --enable-vty-tests --enable-external-tests --enable-werror
$MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
diff --git a/contrib/systemd/osmo-mgw.service b/contrib/systemd/osmo-mgw.service
new file mode 100644
index 0000000..f75277e
--- /dev/null
+++ b/contrib/systemd/osmo-mgw.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Osmocom Media Gateway (MGW)
+
+[Service]
+Type=simple
+Restart=always
+ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
+RestartSec=2
+
+[Install]
+WantedBy=multi-user.target
diff --git a/doc/examples/osmo-mgw/osmo-mgw.cfg b/doc/examples/osmo-mgw/osmo-mgw.cfg
index d8ea3a5..3057369 100644
--- a/doc/examples/osmo-mgw/osmo-mgw.cfg
+++ b/doc/examples/osmo-mgw/osmo-mgw.cfg
@@ -2,12 +2,17 @@
! MGCP configuration example
!
mgcp
- !local ip 10.23.24.2
- !bts ip 10.24.24.1
- !bind ip 10.23.24.1
- bind port 2427
- rtp force-ptime 20
- sdp audio payload number 98
- sdp audio payload name AMR/8000
- number endpoints 31
- no rtcp-omit
+ bind ip 127.0.0.1
+ rtp port-range 4002 16000
+ rtp bind-ip 10.9.1.122
+ rtp ip-probing
+ rtp ip-tos 184
+ bind port 2427
+ sdp audio payload number 98
+ sdp audio payload name GSM
+ number endpoints 31
+ loop 0
+ force-realloc 1
+ rtcp-omit
+ rtp-patch ssrc
+ rtp-patch timestamp
diff --git a/include/Makefile.am b/include/Makefile.am
index b52e5ea..e8fc211 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -7,6 +7,7 @@ nobase_include_HEADERS = \
osmocom/legacy_mgcp/mgcp_internal.h \
osmocom/legacy_mgcp/osmux.h \
osmocom/mgcp_client/mgcp_client.h \
+ osmocom/mgcp_client/mgcp_client_fsm.h \
osmocom/mgcp_client/mgcp_common.h \
osmocom/mgcp/mgcp.h \
osmocom/mgcp/mgcp_common.h \
diff --git a/include/osmocom/legacy_mgcp/vty.h b/include/osmocom/legacy_mgcp/vty.h
index c277c0a..bf6b7a8 100644
--- a/include/osmocom/legacy_mgcp/vty.h
+++ b/include/osmocom/legacy_mgcp/vty.h
@@ -1,31 +1,8 @@
-#ifndef OPENBSC_VTY_H
-#define OPENBSC_VTY_H
+#pragma once
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/buffer.h>
#include <osmocom/vty/command.h>
-struct gsm_network;
-struct vty;
-
-void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
-
-struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
-
-extern struct cmd_element cfg_description_cmd;
-extern struct cmd_element cfg_no_description_cmd;
-
enum mgcp_vty_node {
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
TRUNK_NODE,
};
-
-struct log_info;
-int bsc_vty_init(struct gsm_network *network);
-int bsc_vty_init_extra(void);
-
-void msc_vty_init(struct gsm_network *msc_network);
-
-struct gsm_network *gsmnet_from_vty(struct vty *vty);
-
-#endif
diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am
index d706807..7e297e4 100644
--- a/include/osmocom/mgcp/Makefile.am
+++ b/include/osmocom/mgcp/Makefile.am
@@ -3,7 +3,7 @@ noinst_HEADERS = \
mgcp_msg.h \
mgcp_conn.h \
mgcp_stat.h \
- mgcp_ep.h \
+ mgcp_endp.h \
mgcp_sdp.h \
debug.h \
$(NULL)
diff --git a/include/osmocom/mgcp/mgcp.h b/include/osmocom/mgcp/mgcp.h
index 42a91d8..bdc8f87 100644
--- a/include/osmocom/mgcp/mgcp.h
+++ b/include/osmocom/mgcp/mgcp.h
@@ -105,12 +105,12 @@ struct mgcp_port_range {
};
/* There are up to three modes in which the keep-alive dummy packet can be
- * sent. The beviour is controlled viw the keepalive_interval member of the
+ * sent. The behaviour is controlled via the keepalive_interval member of the
* trunk config. If that member is set to 0 (MGCP_KEEPALIVE_NEVER) no dummy-
* packet is sent at all and the timer that sends regular dummy packets
* is no longer scheduled. If the keepalive_interval is set to -1, only
* one dummy packet is sent when an CRCX or an MDCX is performed. No timer
- * is scheduled. For all vales greater 0, the a timer is scheduled and the
+ * is scheduled. For all vales greater 0, the timer is scheduled and the
* value is used as interval. See also mgcp_keepalive_timer_cb(),
* handle_modify_con(), and handle_create_con() */
#define MGCP_KEEPALIVE_ONCE (-1)
@@ -151,6 +151,7 @@ struct mgcp_trunk_config {
int rtp_accept_all;
unsigned int number_endpoints;
+ int vty_number_endpoints;
struct mgcp_endpoint *endpoints;
};
@@ -211,6 +212,8 @@ struct mgcp_config {
* message.
*/
uint16_t osmux_dummy;
+ /* domain name of the media gateway */
+ char domain[255+1];
};
/* config management */
@@ -219,7 +222,6 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
enum mgcp_role role);
int mgcp_vty_init(void);
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
-void mgcp_release_endp(struct mgcp_endpoint *endp);
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
/*
diff --git a/include/osmocom/mgcp/mgcp_common.h b/include/osmocom/mgcp/mgcp_common.h
index 0eb1388..d23339f 100644
--- a/include/osmocom/mgcp/mgcp_common.h
+++ b/include/osmocom/mgcp/mgcp_common.h
@@ -68,4 +68,18 @@ static inline int mgcp_msg_terminate_nul(struct msgb *msg)
return 0;
}
+/* Maximum length of the comment field */
+#define MGCP_COMMENT_MAXLEN 256
+
+/* String length of Connection Identifiers
+ * (see also RFC3435 2.1.3.2 Names of Connections) */
+#define MGCP_CONN_ID_LENGTH 32+1
+
+/* String length of Endpoint Identifiers.
+/ (see also RFC3435 section 3.2.1.3) */
+#define MGCP_ENDPOINT_MAXLEN (255*2+1+1)
+
+/* A prefix to denote the virtual trunk (RTP on both ends) */
+#define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"
+
#endif
diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h
index e0ae021..e2a423f 100644
--- a/include/osmocom/mgcp/mgcp_conn.h
+++ b/include/osmocom/mgcp/mgcp_conn.h
@@ -28,12 +28,11 @@
#include <inttypes.h>
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
- uint32_t id, enum mgcp_conn_type type,
- char *name);
-struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, uint32_t id);
+ enum mgcp_conn_type type, char *name);
+struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
- uint32_t id);
-void mgcp_conn_free(struct mgcp_endpoint *endp, uint32_t id);
+ const char *id);
+void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
char *mgcp_conn_dump(struct mgcp_conn *conn);
diff --git a/include/osmocom/mgcp/mgcp_endp.h b/include/osmocom/mgcp/mgcp_endp.h
new file mode 100644
index 0000000..a486dcd
--- /dev/null
+++ b/include/osmocom/mgcp/mgcp_endp.h
@@ -0,0 +1,99 @@
+/* Endpoint types */
+
+/*
+ * (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * 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/>.
+ *
+ */
+
+#pragma once
+
+struct sockaddr_in;
+struct mgcp_conn;
+struct mgcp_endpoint;
+
+/* Callback type for RTP dispatcher functions
+ (e.g mgcp_dispatch_rtp_bridge_cb, see below) */
+typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
+ char *buf, unsigned int buf_size,
+ struct mgcp_conn *conn);
+
+/* Callback type for endpoint specific cleanup actions. This function
+ * is automatically executed when a connection is freed (see mgcp_conn_free()
+ * in mgcp_conn.c). Depending on the type of the endpoint there may be endpoint
+ * specific things to take care of once a connection has been removed. */
+typedef void (*mgcp_cleanup_cp) (struct mgcp_endpoint *endp,
+ struct mgcp_conn *conn);
+
+/*! MGCP endpoint properties */
+struct mgcp_endpoint_type {
+ /*!< maximum number of connections */
+ int max_conns;
+
+ /*!< callback that defines how to dispatch incoming RTP data */
+ mgcp_dispatch_rtp_cb dispatch_rtp_cb;
+
+ /*!< callback that implements endpoint specific cleanup actions */
+ mgcp_cleanup_cp cleanup_cb;
+};
+
+/*! MGCP endpoint typeset */
+struct mgcp_endpoint_typeset {
+ struct mgcp_endpoint_type rtp;
+};
+
+/*! static MGCP endpoint typeset (pre-initalized, read-only) */
+extern const struct mgcp_endpoint_typeset ep_typeset;
+
+/*! MGCP endpoint model */
+struct mgcp_endpoint {
+
+ /*!< Call identifier string (as supplied by the call agant) */
+ char *callid;
+
+ /*!< Local connection options (see mgcp_intermal.h) */
+ struct mgcp_lco local_options;
+
+ /*!< List with connections active on this endpoint */
+ struct llist_head conns;
+
+ /*!< Backpointer to the MGW configuration */
+ struct mgcp_config *cfg;
+
+ /*!< Backpointer to the Trunk specific configuration */
+ struct mgcp_trunk_config *tcfg;
+
+ /*!< Endpoint properties (see above) */
+ const struct mgcp_endpoint_type *type;
+
+ /*!< Last MGCP transmission (in case re-transmission is required) */
+ char *last_trans;
+
+ /*!< Last MGCP response (in case re-transmission is required) */
+ char *last_response;
+
+ /*!< Memorize if this endpoint was choosen by the MGW (wildcarded, true)
+ * or if the user has choosen the particular endpoint explicitly. */
+ bool wildcarded_req;
+};
+
+/*! Extract endpoint number for a given endpoint */
+#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
+
+void mgcp_endp_release(struct mgcp_endpoint *endp);
+
diff --git a/include/osmocom/mgcp/mgcp_ep.h b/include/osmocom/mgcp/mgcp_ep.h
deleted file mode 100644
index e477a47..0000000
--- a/include/osmocom/mgcp/mgcp_ep.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Endpoint types */
-
-/*
- * (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- *
- */
-
-#pragma once
-
-struct sockaddr_in;
-struct mgcp_conn;
-
-/* Callback type for RTP dispatcher functions
- (e.g mgcp_dispatch_rtp_bridge_cb, see below) */
-typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in * addr,
- char *buf, unsigned int buf_size,
- struct mgcp_conn * conn);
-
-/*! MGCP endpoint properties */
-struct mgcp_endpoint_type {
- /*!< maximum number of connections */
- int max_conns;
-
- /*!< callback that defines how to dispatch incoming RTP data */
- mgcp_dispatch_rtp_cb dispatch_rtp_cb;
-};
-
-/*! MGCP endpoint typeset */
-struct mgcp_endpoint_typeset {
- struct mgcp_endpoint_type rtp;
-};
-
-/*! static MGCP endpoint typeset (pre-initalized, read-only) */
-extern const struct mgcp_endpoint_typeset ep_typeset;
diff --git a/include/osmocom/mgcp/mgcp_internal.h b/include/osmocom/mgcp/mgcp_internal.h
index b9c1731..0da2c56 100644
--- a/include/osmocom/mgcp/mgcp_internal.h
+++ b/include/osmocom/mgcp/mgcp_internal.h
@@ -27,11 +27,14 @@
#include <osmocom/core/select.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/counter.h>
#define CI_UNUSED 0
-#define CONN_ID_BTS 0
-#define CONN_ID_NET 1
+/* FIXME: This this is only needed to compile the currently
+ * broken OSMUX support. Remove when fixed */
+#define CONN_ID_BTS "0"
+#define CONN_ID_NET "1"
enum mgcp_trunk_type {
MGCP_TRUNK_VIRTUAL,
@@ -48,27 +51,37 @@ struct mgcp_rtp_stream_state {
};
struct mgcp_rtp_state {
+ /* has this state structure been initialized? */
int initialized;
- int patch_ssrc;
- uint32_t orig_ssrc;
-
- int seq_offset;
-
- int32_t timestamp_offset;
+ struct {
+ /* are we patching the SSRC value? */
+ int patch_ssrc;
+ /* original SSRC (to which we shall patch any different SSRC) */
+ uint32_t orig_ssrc;
+ /* offset to apply on the sequence number */
+ int seq_offset;
+ /* offset to apply on the timestamp number */
+ int32_t timestamp_offset;
+ } patch;
+
+ /* duration of a packet (FIXME: in which unit?) */
uint32_t packet_duration;
struct mgcp_rtp_stream_state in_stream;
struct mgcp_rtp_stream_state out_stream;
/* jitter and packet loss calculation */
- int stats_initialized;
- uint16_t stats_base_seq;
- uint16_t stats_max_seq;
- uint32_t stats_ssrc;
- uint32_t stats_jitter;
- int32_t stats_transit;
- int stats_cycles;
+ struct {
+ int initialized;
+ uint16_t base_seq;
+ uint16_t max_seq;
+ uint32_t ssrc;
+ uint32_t jitter;
+ int32_t transit;
+ int cycles;
+ } stats;
+
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
};
@@ -83,13 +96,18 @@ struct mgcp_rtp_codec {
char *subtype_name;
};
+/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
/* statistics */
- unsigned int packets_rx;
- unsigned int octets_rx;
- unsigned int packets_tx;
- unsigned int octets_tx;
- unsigned int dropped_packets;
+ struct {
+ unsigned int packets_rx;
+ unsigned int octets_rx;
+ unsigned int packets_tx;
+ unsigned int octets_tx;
+ unsigned int dropped_packets;
+ } stats;
+
+ /* local IP address of the RTP socket */
struct in_addr addr;
/* in network byte order */
@@ -103,23 +121,30 @@ struct mgcp_rtp_end {
int frames_per_packet;
uint32_t packet_duration_ms;
char *fmtp_extra;
+ /* are we transmitting packets (1) or dropping (0) outbound packets */
int 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;
+ /* FIXME: not used anymore, used to be [external] transcoding related */
void *rtp_process_data;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_fd rtp;
struct osmo_fd rtcp;
+ /* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
};
struct mgcp_rtp_tap {
+ /* is this tap active (1) or not (0) */
int enabled;
+ /* IP/port to which we're forwarding the tapped data */
struct sockaddr_in forward;
};
@@ -155,7 +180,7 @@ struct mgcp_conn_rtp {
/* Sequence bits */
struct mgcp_rtp_state state;
- /* taps for the rtp connection */
+ /* taps for the rtp connection; one per direction */
struct mgcp_rtp_tap tap_in;
struct mgcp_rtp_tap tap_out;
@@ -202,8 +227,8 @@ struct mgcp_conn {
/*!< copy of the mode to restore the original setting (VTY) */
enum mgcp_connection_mode mode_orig;
- /*!< connection id to identify the conntion */
- uint32_t id;
+ /*!< connection id to identify the connection */
+ char id[MGCP_CONN_ID_LENGTH];
/*!< human readable name (vty, logging) */
char name[256];
@@ -221,25 +246,9 @@ struct mgcp_conn {
struct mgcp_endpoint_type;
-struct mgcp_endpoint {
- char *callid;
- struct mgcp_lco local_options;
- struct llist_head conns;
-
- /* backpointer */
- struct mgcp_config *cfg;
- struct mgcp_trunk_config *tcfg;
-
- const struct mgcp_endpoint_type *type;
-
- /* fields for re-transmission */
- char *last_trans;
- char *last_response;
-};
-#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
/**
* Internal structure while parsing a request
@@ -249,7 +258,6 @@ struct mgcp_parse_data {
struct mgcp_endpoint *endp;
char *trans;
char *save;
- int found;
};
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
@@ -258,6 +266,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size, struct mgcp_conn *conn);
+void mgcp_cleanup_rtp_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);
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
diff --git a/include/osmocom/mgcp/mgcp_msg.h b/include/osmocom/mgcp/mgcp_msg.h
index b7d52bb..7732865 100644
--- a/include/osmocom/mgcp/mgcp_msg.h
+++ b/include/osmocom/mgcp/mgcp_msg.h
@@ -43,7 +43,7 @@ int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
-int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *ci);
+int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id);
char *mgcp_strline(char *str, char **saveptr);
@@ -54,5 +54,3 @@ char *mgcp_strline(char *str, char **saveptr);
#define for_each_non_empty_line(line, save)\
for (line = strtok_r(NULL, "\r\n", &save); line;\
line = strtok_r(NULL, "\r\n", &save))
-
-int mgcp_parse_ci(uint32_t *conn_id, const char *ci);
diff --git a/include/osmocom/mgcp/vty.h b/include/osmocom/mgcp/vty.h
index c277c0a..bf6b7a8 100644
--- a/include/osmocom/mgcp/vty.h
+++ b/include/osmocom/mgcp/vty.h
@@ -1,31 +1,8 @@
-#ifndef OPENBSC_VTY_H
-#define OPENBSC_VTY_H
+#pragma once
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/buffer.h>
#include <osmocom/vty/command.h>
-struct gsm_network;
-struct vty;
-
-void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
-
-struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
-
-extern struct cmd_element cfg_description_cmd;
-extern struct cmd_element cfg_no_description_cmd;
-
enum mgcp_vty_node {
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
TRUNK_NODE,
};
-
-struct log_info;
-int bsc_vty_init(struct gsm_network *network);
-int bsc_vty_init_extra(void);
-
-void msc_vty_init(struct gsm_network *msc_network);
-
-struct gsm_network *gsmnet_from_vty(struct vty *vty);
-
-#endif
diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h
index e91b190..73f3bba 100644
--- a/include/osmocom/mgcp_client/mgcp_client.h
+++ b/include/osmocom/mgcp_client/mgcp_client.h
@@ -27,9 +27,11 @@ struct mgcp_client_conf {
typedef unsigned int mgcp_trans_id_t;
struct mgcp_response_head {
- int response_code;
- mgcp_trans_id_t trans_id;
- const char *comment;
+ int response_code;
+ mgcp_trans_id_t trans_id;
+ char comment[MGCP_COMMENT_MAXLEN];
+ char conn_id[MGCP_CONN_ID_LENGTH];
+ char endpoint[MGCP_ENDPOINT_MAXLEN];
};
struct mgcp_response {
@@ -54,18 +56,15 @@ enum mgcp_verb {
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
-/* See also RFC3435 section 3.2.1.3 */
-#define MGCP_ENDPOINT_MAXLEN (255*2+1+1)
-
struct mgcp_msg {
enum mgcp_verb verb;
/* See MGCP_MSG_PRESENCE_* constants */
uint32_t presence;
char endpoint[MGCP_ENDPOINT_MAXLEN];
unsigned int call_id;
- uint32_t conn_id;
- uint16_t audio_port;
- char *audio_ip;
+ char *conn_id;
+ uint16_t audio_port;
+ char *audio_ip;
enum mgcp_connection_mode conn_mode;
};
@@ -92,6 +91,7 @@ int mgcp_response_parse_params(struct mgcp_response *r);
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
+int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
enum mgcp_connection_mode;
@@ -110,6 +110,7 @@ struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
+mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
extern const struct value_string mgcp_client_connection_mode_strs[];
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
diff --git a/include/osmocom/mgcp_client/mgcp_client_fsm.h b/include/osmocom/mgcp_client/mgcp_client_fsm.h
new file mode 100644
index 0000000..7d06178
--- /dev/null
+++ b/include/osmocom/mgcp_client/mgcp_client_fsm.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <osmocom/mgcp_client/mgcp_common.h>
+#include <osmocom/mgcp_client/mgcp_client.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+/*! This struct organizes the connection infromation one connection side
+ * (either remote or local). It is used to pass parameters (local) to the FSM
+ * and get responses (remote) from the FSM as pointer attached to the FSM
+ * event.
+ *
+ * When modifiying a connection, the endpoint and call_id members may be left
+ * unpopulated. The call_id field is ignored in this case. If an endpoint
+ * identifier is supplied it is checked against the internal state to make
+ * sure it is correct. */
+struct mgcp_conn_peer {
+ /*!< RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
+ char addr[INET_ADDRSTRLEN];
+
+ /*!< RTP connection IP-Port (optional) */
+ uint16_t port;
+
+ /*!< RTP endpoint */
+ char endpoint[MGCP_ENDPOINT_MAXLEN];
+
+ /*!< CALL ID (unique per connection) */
+ unsigned int call_id;
+};
+
+struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
+ uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
+int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
+void mgcp_conn_delete(struct osmo_fsm_inst *fi);
diff --git a/libosmo-mgcp.pc.in b/libosmo-mgcp.pc.in
deleted file mode 100644
index 63b794a..0000000
--- a/libosmo-mgcp.pc.in
+++ /dev/null
@@ -1,10 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Osmocom Media Gateway Control Protocol library
-Description: C Utility Library
-Version: @VERSION@
-Libs: -L${libdir} -losmo-mgcp
-Cflags: -I${includedir}/
diff --git a/src/libosmo-legacy-mgcp/Makefile.am b/src/libosmo-legacy-mgcp/Makefile.am
index 9160586..4ee4e6a 100644
--- a/src/libosmo-legacy-mgcp/Makefile.am
+++ b/src/libosmo-legacy-mgcp/Makefile.am
@@ -24,7 +24,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!
-LEGACY_MGCP_LIBVERSION=0:0:0
+LEGACY_MGCP_LIBVERSION=0:1:0
lib_LTLIBRARIES = \
libosmo-legacy-mgcp.la \
diff --git a/src/libosmo-legacy-mgcp/mgcp_protocol.c b/src/libosmo-legacy-mgcp/mgcp_protocol.c
index bc1ec0d..4e82233 100644
--- a/src/libosmo-legacy-mgcp/mgcp_protocol.c
+++ b/src/libosmo-legacy-mgcp/mgcp_protocol.c
@@ -372,8 +372,8 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
- /* attempt to treat it as a response */
- if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
+ /* attempt to treat it as a response */
+ if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
return NULL;
}
@@ -1588,24 +1588,26 @@ void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
msg += nchars;
size -= nchars;
- /* Error Counter */
- nchars = snprintf(msg, size,
- "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
- endp->net_state.in_stream.err_ts_counter,
- endp->net_state.out_stream.err_ts_counter,
- endp->bts_state.in_stream.err_ts_counter,
- endp->bts_state.out_stream.err_ts_counter);
- if (nchars < 0 || nchars >= size)
- goto truncate;
-
- msg += nchars;
- size -= nchars;
-
- if (endp->osmux.state == OSMUX_STATE_ENABLED) {
- snprintf(msg, size,
- "\r\nX-Osmux-ST: CR=%u, BR=%u",
- endp->osmux.stats.chunks,
- endp->osmux.stats.octets);
+ if (endp->cfg->osmux != OSMUX_USAGE_OFF) {
+ /* Error Counter */
+ nchars = snprintf(msg, size,
+ "\r\nX-Osmo-CP: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
+ endp->net_state.in_stream.err_ts_counter,
+ endp->net_state.out_stream.err_ts_counter,
+ endp->bts_state.in_stream.err_ts_counter,
+ endp->bts_state.out_stream.err_ts_counter);
+ if (nchars < 0 || nchars >= size)
+ goto truncate;
+
+ msg += nchars;
+ size -= nchars;
+
+ if (endp->osmux.state == OSMUX_STATE_ENABLED) {
+ snprintf(msg, size,
+ "\r\nX-Osmux-ST: CR=%u, BR=%u",
+ endp->osmux.stats.chunks,
+ endp->osmux.stats.octets);
+ }
}
truncate:
msg[size - 1] = '\0';
diff --git a/src/libosmo-mgcp-client/Makefile.am b/src/libosmo-mgcp-client/Makefile.am
index 1e4e764..01371d7 100644
--- a/src/libosmo-mgcp-client/Makefile.am
+++ b/src/libosmo-mgcp-client/Makefile.am
@@ -20,7 +20,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=2:0:0
+MGCP_CLIENT_LIBVERSION=3:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
@@ -29,6 +29,7 @@ lib_LTLIBRARIES = \
libosmo_mgcp_client_la_SOURCES = \
mgcp_client.c \
mgcp_client_vty.c \
+ mgcp_client_fsm.c \
$(NULL)
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c
index f8c55ac..e054593 100644
--- a/src/libosmo-mgcp-client/mgcp_client.c
+++ b/src/libosmo-mgcp-client/mgcp_client.c
@@ -4,16 +4,16 @@
* 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
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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.
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
+ * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -24,6 +24,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/byteswap.h>
+#include <osmocom/core/socket.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
@@ -35,6 +36,8 @@
#include <unistd.h>
#include <string.h>
+/*! Initalize MGCP client configuration struct with default values.
+ * \param[out] conf Client configuration.*/
void mgcp_client_conf_init(struct mgcp_client_conf *conf)
{
/* NULL and -1 default to MGCP_CLIENT_*_DEFAULT values */
@@ -61,7 +64,9 @@ static bool endpoint_in_use(uint16_t id, struct mgcp_client *client)
return false;
}
-/* Find and seize an unsused endpoint id */
+/*! Pick next free endpoint ID.
+ * \param[in,out] client MGCP client descriptor.
+ * \returns 0 on success, -EINVAL on error. */
int mgcp_client_next_endpoint(struct mgcp_client *client)
{
int i;
@@ -94,6 +99,9 @@ int mgcp_client_next_endpoint(struct mgcp_client *client)
return -EINVAL;
}
+/*! Release a seized endpoint ID to make it available again for other calls.
+ * \param[in] id Endpoint ID
+ * \param[in,out] client MGCP client descriptor. */
/* Release a seized endpoint id to make it available again for other calls */
void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client)
{
@@ -133,20 +141,17 @@ static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
r->body = (char *)msg->data;
- if (sscanf(r->body, "%3d %u %n",
+ if (sscanf(r->body, "%3d %u %n",
&r->head.response_code, &r->head.trans_id,
&comment_pos) != 2)
goto response_parse_failure;
- r->head.comment = r->body + comment_pos;
+ osmo_strlcpy(r->head.comment, r->body + comment_pos, sizeof(r->head.comment));
end = strchr(r->head.comment, '\r');
if (!end)
goto response_parse_failure;
/* Mark the end of the comment */
*end = '\0';
- r->body = end + 1;
- if (r->body[0] == '\n')
- r->body ++;
return 0;
response_parse_failure:
@@ -176,10 +181,13 @@ static bool mgcp_line_is_valid(const char *line)
/* Parse a line like "m=audio 16002 RTP/AVP 98" */
static int mgcp_parse_audio_port(struct mgcp_response *r, const char *line)
{
- if (sscanf(line, "m=audio %hu",
+ if (sscanf(line, "m=audio %hu",
&r->audio_port) != 1)
goto response_parse_failure;
+ if (r->audio_port == 0)
+ goto response_parse_failure;
+
return 0;
response_parse_failure:
@@ -201,8 +209,7 @@ static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
goto response_parse_failure;
/* Extract IP-Address */
- strncpy(r->audio_ip, line + 9, sizeof(r->audio_ip));
- r->audio_ip[sizeof(r->audio_ip) - 1] = '\0';
+ osmo_strlcpy(r->audio_ip, line + 9, sizeof(r->audio_ip));
/* Check IP-Address */
if (inet_aton(r->audio_ip, &ip_test) == 0)
@@ -216,26 +223,56 @@ response_parse_failure:
return -EINVAL;
}
+/* A new section is marked by a double line break, check a few more
+ * patterns as there may be variants */
+static char *mgcp_find_section_end(char *string)
+{
+ char *rc;
+
+ rc = strstr(string, "\n\n");
+ if (rc)
+ return rc;
+
+ rc = strstr(string, "\n\r\n\r");
+ if (rc)
+ return rc;
+
+ rc = strstr(string, "\r\n\r\n");
+ if (rc)
+ return rc;
+
+ return NULL;
+}
+
+/*! Parse body (SDP) parameters of the MGCP response
+ * \param[in,out] r Response data
+ * \returns 0 on success, -EINVAL on error. */
int mgcp_response_parse_params(struct mgcp_response *r)
{
char *line;
int rc;
+ char *data;
+ char *data_ptr;
+
+ /* Since this functions performs a destructive parsing, we create a
+ * local copy of the body data */
OSMO_ASSERT(r->body);
- char *data = strstr(r->body, "\n\n");
+ data = talloc_strdup(r, r->body);
+ OSMO_ASSERT(data);
- if (!data) {
+ /* Find beginning of the parameter (SDP) section */
+ data_ptr = mgcp_find_section_end(data);
+ if (!data_ptr) {
LOGP(DLMGCP, LOGL_ERROR,
- "MGCP response: cannot find start of parameters\n");
- return -EINVAL;
+ "MGCP response: cannot find start of SDP parameters\n");
+ rc = -EINVAL;
+ goto exit;
}
- /* Advance to after the \n\n, replace the second \n with \0. That's
- * where the parameters start. */
- data ++;
- *data = '\0';
- data ++;
+ /* data_ptr now points to the beginning of the section-end-marker; for_each_non_empty_line()
+ * skips any \r and \n characters for free, so we don't need to skip the marker. */
- for_each_non_empty_line(line, data) {
+ for_each_non_empty_line(line, data_ptr) {
if (!mgcp_line_is_valid(line))
return -EINVAL;
@@ -243,30 +280,122 @@ int mgcp_response_parse_params(struct mgcp_response *r)
case 'm':
rc = mgcp_parse_audio_port(r, line);
if (rc)
- return rc;
+ goto exit;
break;
case 'c':
rc = mgcp_parse_audio_ip(r, line);
if (rc)
- return rc;
+ goto exit;
break;
default:
/* skip unhandled parameters */
break;
}
}
+
+ rc = 0;
+exit:
+ talloc_free(data);
+ return rc;
+}
+
+/* Parse a line like "X: something" */
+static int mgcp_parse_head_param(char *result, unsigned int result_len,
+ char label, const char *line)
+{
+ char label_string[4];
+
+ /* Detect empty parameters */
+ if (strlen(line) < 4)
+ goto response_parse_failure;
+
+ /* Check if the label matches */
+ snprintf(label_string, sizeof(label_string), "%c: ", label);
+ if (memcmp(label_string, line, 3) != 0)
+ goto response_parse_failure;
+
+ /* Copy payload part of the string to destinations (the label string
+ * is always 3 chars long) */
+ osmo_strlcpy(result, line + 3, result_len);
return 0;
+
+response_parse_failure:
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Failed to parse MGCP response (parameter label: %c)\n", label);
+ return -EINVAL;
+}
+
+/* Parse MGCP parameters of the response */
+static int parse_head_params(struct mgcp_response *r)
+{
+ char *line;
+ int rc = 0;
+ OSMO_ASSERT(r->body);
+ char *data;
+ char *data_ptr;
+ char *data_end;
+
+ /* Since this functions performs a destructive parsing, we create a
+ * local copy of the body data */
+ data = talloc_zero_size(r, strlen(r->body)+1);
+ OSMO_ASSERT(data);
+ data_ptr = data;
+ osmo_strlcpy(data, r->body, strlen(r->body));
+
+ /* If there is an SDP body attached, prevent for_each_non_empty_line()
+ * into running in there, we are not yet interested in the parameters
+ * stored there. */
+ data_end = mgcp_find_section_end(data);
+ if (data_end)
+ *data_end = '\0';
+
+ for_each_non_empty_line(line, data_ptr) {
+ switch (line[0]) {
+ case 'Z':
+ rc = mgcp_parse_head_param(r->head.endpoint,
+ sizeof(r->head.endpoint),
+ 'Z', line);
+ if (rc)
+ goto exit;
+
+ /* A specific endpoint identifier returned by the MGW
+ * must not contain any wildcard characters */
+ if (strstr(r->head.endpoint, "*") != NULL) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* A specific endpoint identifier returned by the MGW
+ * must contain an @ character */
+ if (strstr(r->head.endpoint, "@") == NULL) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ break;
+ case 'I':
+ rc = mgcp_parse_head_param(r->head.conn_id,
+ sizeof(r->head.conn_id),
+ 'I', line);
+ if (rc)
+ goto exit;
+ break;
+ default:
+ /* skip unhandled parameters */
+ break;
+ }
+ }
+exit:
+ talloc_free(data);
+ return rc;
}
static struct mgcp_response_pending *mgcp_client_response_pending_get(
struct mgcp_client *mgcp,
- struct mgcp_response *r)
+ mgcp_trans_id_t trans_id)
{
struct mgcp_response_pending *pending;
- if (!r)
- return NULL;
llist_for_each_entry(pending, &mgcp->responses_pending, entry) {
- if (pending->trans_id == r->head.trans_id) {
+ if (pending->trans_id == trans_id) {
llist_del(&pending->entry);
return pending;
}
@@ -282,26 +411,42 @@ static struct mgcp_response_pending *mgcp_client_response_pending_get(
*/
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
{
- struct mgcp_response r = { 0 };
+ struct mgcp_response *r;
struct mgcp_response_pending *pending;
int rc;
- rc = mgcp_response_parse_head(&r, msg);
+ r = talloc_zero(mgcp, struct mgcp_response);
+ OSMO_ASSERT(r);
+
+ rc = mgcp_response_parse_head(r, msg);
if (rc) {
- LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response\n");
- return -1;
+ LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
+ rc = 1;
+ goto error;
}
- pending = mgcp_client_response_pending_get(mgcp, &r);
+ rc = parse_head_params(r);
+ if (rc) {
+ LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
+ rc = 1;
+ goto error;
+ }
+
+ pending = mgcp_client_response_pending_get(mgcp, r->head.trans_id);
if (!pending) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find matching MGCP transaction for trans_id %d\n",
- r.head.trans_id);
- return -1;
+ r->head.trans_id);
+ rc = -ENOENT;
+ goto error;
}
- mgcp_client_handle_response(mgcp, pending, &r);
- return 0;
+ mgcp_client_handle_response(mgcp, pending, r);
+ rc = 0;
+
+error:
+ talloc_free(r);
+ return rc;
}
static int mgcp_do_read(struct osmo_fd *fd)
@@ -325,7 +470,7 @@ static int mgcp_do_read(struct osmo_fd *fd)
LOGP(DLMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
msgb_free(msg);
return -1;
- }
+ }
msg->l2h = msgb_put(msg, ret);
ret = mgcp_client_rx(mgcp, msg);
@@ -340,7 +485,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
unsigned int i;
- strncpy(strbuf, (const char*)msg->data, l);
+ osmo_strlcpy(strbuf, (const char*)msg->data, l);
for (i = 0; i < sizeof(strbuf); i++) {
if (strbuf[i] == '\n' || strbuf[i] == '\r') {
strbuf[i] = '\0';
@@ -388,9 +533,11 @@ struct mgcp_client *mgcp_client_init(void *ctx,
return mgcp;
}
+/*! Initalize client connection (opens socket only, no request is sent yet)
+ * \param[in,out] mgcp MGCP client descriptor.
+ * \returns 0 on success, -EINVAL on error. */
int mgcp_client_connect(struct mgcp_client *mgcp)
{
- int on;
struct sockaddr_in addr;
struct osmo_wqueue *wq;
int rc;
@@ -402,46 +549,19 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
wq = &mgcp->wq;
- wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (wq->bfd.fd < 0) {
- LOGP(DLMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
- return -errno;
- }
-
- on = 1;
- if (setsockopt(wq->bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
- LOGP(DLMGCP, LOGL_FATAL,
- "Failed to initialize socket for MGCP GW: %s\n",
- strerror(errno));
- rc = -errno;
- goto error_close_fd;
- }
-
- /* bind socket */
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- inet_aton(mgcp->actual.local_addr, &addr.sin_addr);
- addr.sin_port = htons(mgcp->actual.local_port);
- if (bind(wq->bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ rc = osmo_sock_init2_ofd(&wq->bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ mgcp->actual.local_addr, mgcp->actual.local_port,
+ mgcp->actual.remote_addr, mgcp->actual.remote_port,
+ OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
+ if (rc < 0) {
LOGP(DLMGCP, LOGL_FATAL,
- "Failed to bind for MGCP GW to %s %u\n",
- mgcp->actual.local_addr, mgcp->actual.local_port);
- rc = -errno;
+ "Failed to initialize socket %s:%u -> %s:%u for MGCP GW: %s\n",
+ mgcp->actual.local_addr, mgcp->actual.local_port,
+ mgcp->actual.remote_addr, mgcp->actual.remote_port, strerror(errno));
goto error_close_fd;
}
- /* connect to the remote */
inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
- addr.sin_port = htons(mgcp->actual.remote_port);
- if (connect(wq->bfd.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- LOGP(DLMGCP, LOGL_FATAL,
- "Failed to connect to MGCP GW at %s %u: %s\n",
- mgcp->actual.remote_addr, mgcp->actual.remote_port,
- strerror(errno));
- rc = -errno;
- goto error_close_fd;
- }
-
mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
osmo_wqueue_init(wq, 10);
@@ -450,11 +570,6 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
wq->read_cb = mgcp_do_read;
wq->write_cb = mgcp_do_write;
- if (osmo_fd_register(&wq->bfd) != 0) {
- LOGP(DLMGCP, LOGL_FATAL, "Failed to register BFD\n");
- rc = -EIO;
- goto error_close_fd;
- }
LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s:%u -> %s:%u\n",
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port);
@@ -466,17 +581,25 @@ error_close_fd:
return rc;
}
+/*! Get the IP-Aaddress of the associated MGW as string.
+ * \param[in] mgcp MGCP client descriptor.
+ * \returns a pointer to the address string. */
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp)
{
return mgcp->actual.remote_addr;
}
+/*! Get the IP-Port of the associated MGW.
+ * \param[in] mgcp MGCP client descriptor.
+ * \returns port number. */
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp)
{
return mgcp->actual.remote_port;
}
-/* Return the MGCP GW binary IPv4 address in network byte order. */
+/*! Get the IP-Aaddress of the associated MGW as its numeric representation.
+ * \param[in] mgcp MGCP client descriptor.
+ * \returns IP-Address as 32 bit integer (network byte order) */
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
{
return mgcp->remote_addr;
@@ -503,7 +626,10 @@ struct mgcp_response_pending * mgcp_client_pending_add(
* response_cb. NOTE: the response_cb still needs to call
* mgcp_response_parse_params(response) to get the parsed parameters -- to
* potentially save some CPU cycles, only the head line has been parsed when
- * the response_cb is invoked. */
+ * the response_cb is invoked.
+ * Before the priv pointer becomes invalid, e.g. due to transaction timeout,
+ * mgcp_client_cancel() needs to be called for this transaction.
+ */
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv)
{
@@ -546,6 +672,35 @@ mgcp_tx_error:
return -1;
}
+/*! Cancel a pending transaction.
+ * \param[in] mgcp MGCP client descriptor.
+ * \param[in,out] trans_id Transaction id.
+ * \returns 0 on success, -ENOENT on error.
+ *
+ * Should a priv pointer passed to mgcp_client_tx() become invalid, this function must be called. In
+ * practical terms, if the caller of mgcp_client_tx() wishes to tear down a transaction without having
+ * received a response this function must be called. The trans_id can be obtained by calling
+ * mgcp_msg_trans_id() on the msgb produced by mgcp_msg_gen(). */
+int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id)
+{
+ struct mgcp_response_pending *pending = mgcp_client_response_pending_get(mgcp, trans_id);
+ if (!pending) {
+ /*! Note: it is not harmful to cancel a transaction twice. */
+ LOGP(DLMGCP, LOGL_INFO, "Cannot cancel, no such transaction: %u\n", trans_id);
+ return -ENOENT;
+ }
+ LOGP(DLMGCP, LOGL_INFO, "Canceled transaction %u\n", trans_id);
+ talloc_free(pending);
+ return 0;
+ /*! We don't really need to clean up the wqueue: In all sane cases, the msgb has already been sent
+ * out and is no longer in the wqueue. If it still is in the wqueue, then sending MGCP messages
+ * per se is broken and the program should notice so by a full wqueue. Even if this was called
+ * before we had a chance to send out the message and it is still going to be sent, we will just
+ * ignore the reply to it later. Removing a msgb from the wqueue here would just introduce more
+ * bug surface in terms of failing to update wqueue API's counters or some such.
+ */
+}
+
static struct msgb *mgcp_msg_from_buf(mgcp_trans_id_t trans_id,
const char *buf, int len)
{
@@ -650,20 +805,25 @@ struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
#define MGCP_CRCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
MGCP_MSG_PRESENCE_CALL_ID | \
- MGCP_MSG_PRESENCE_CONN_ID | \
MGCP_MSG_PRESENCE_CONN_MODE)
#define MGCP_MDCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
+ MGCP_MSG_PRESENCE_CALL_ID | \
MGCP_MSG_PRESENCE_CONN_ID)
#define MGCP_DLCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT)
#define MGCP_AUEP_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT)
#define MGCP_RSIP_MANDATORY 0 /* none */
+/*! Generate an MGCP message
+ * \param[in] mgcp MGCP client descriptor.
+ * \param[in] mgcp_msg Message description
+ * \returns message buffer on success, NULL on error. */
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
{
mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
uint32_t mandatory_mask;
struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
int rc = 0;
+ char local_ip[INET_ADDRSTRLEN];
msg->l2h = msg->data;
msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
@@ -706,8 +866,23 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
}
/* Add endpoint name */
- if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT)
+ if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
+ if (strlen(mgcp_msg->endpoint) <= 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Empty endpoint name, can not generate MGCP message\n");
+ msgb_free(msg);
+ return NULL;
+ }
+
+ if (strstr(mgcp_msg->endpoint, "@") == NULL) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
+ mgcp_msg->endpoint);
+ msgb_free(msg);
+ }
+
rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
+ }
/* Add protocol version */
rc += msgb_printf(msg, " MGCP 1.0\r\n");
@@ -717,12 +892,18 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
rc += msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
/* Add connection id */
- if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID)
- rc += msgb_printf(msg, "I: %u\r\n", mgcp_msg->conn_id);
+ if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
+ if (strlen(mgcp_msg->conn_id) <= 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Empty connection id, can not generate MGCP message\n");
+ msgb_free(msg);
+ return NULL;
+ }
+ rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
+ }
/* Add local connection options */
- if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID
- && mgcp_msg->verb == MGCP_VERB_CRCX)
+ if (mgcp_msg->verb == MGCP_VERB_CRCX)
rc += msgb_printf(msg, "L: p:20, a:AMR, nt:IN\r\n");
/* Add mode */
@@ -731,11 +912,49 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
msgb_printf(msg, "M: %s\r\n",
mgcp_client_cmode_name(mgcp_msg->conn_mode));
- /* Add RTP address and port (SDP) */
+ /* Add SDP body */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
&& mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT) {
+
+ /* Add separator to mark the beginning of the SDP block */
rc += msgb_printf(msg, "\r\n");
+
+ /* Add SDP protocol version */
+ rc += msgb_printf(msg, "v=0\r\n");
+
+ /* Determine local IP-Address */
+ if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Could not determine local IP-Address!\n");
+ msgb_free(msg);
+ return NULL;
+ }
+
+ /* Add owner/creator (SDP) */
+ rc += msgb_printf(msg, "o=- %x 23 IN IP4 %s\r\n",
+ mgcp_msg->call_id, local_ip);
+
+ /* Add session name (none) */
+ rc += msgb_printf(msg, "s=-\r\n");
+
+ /* Add RTP address and port */
+ if (mgcp_msg->audio_port == 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Invalid port number, can not generate MGCP message\n");
+ msgb_free(msg);
+ return NULL;
+ }
+ if (strlen(mgcp_msg->audio_ip) <= 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "Empty ip address, can not generate MGCP message\n");
+ msgb_free(msg);
+ return NULL;
+ }
rc += msgb_printf(msg, "c=IN IP4 %s\r\n", mgcp_msg->audio_ip);
+
+ /* Add time description, active time (SDP) */
+ rc += msgb_printf(msg, "t=0 0\r\n");
+
rc +=
msgb_printf(msg, "m=audio %u RTP/AVP 255\r\n",
mgcp_msg->audio_port);
@@ -751,6 +970,17 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
return msg;
}
+/*! Retrieve the MGCP transaction ID from a msgb generated by mgcp_msg_gen()
+ * \param[in] msg message buffer
+ * \returns Transaction id. */
+mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg)
+{
+ return (mgcp_trans_id_t)msg->cb[MSGB_CB_MGCP_TRANS_ID];
+}
+
+/*! Get the configuration parameters a given MGCP client instance
+ * \param[in] mgcp MGCP client descriptor.
+ * \returns configuration */
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
{
return &mgcp->actual;
diff --git a/src/libosmo-mgcp-client/mgcp_client_fsm.c b/src/libosmo-mgcp-client/mgcp_client_fsm.c
new file mode 100644
index 0000000..3c755be
--- /dev/null
+++ b/src/libosmo-mgcp-client/mgcp_client_fsm.c
@@ -0,0 +1,669 @@
+/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/mgcp_client/mgcp_client.h>
+#include <osmocom/mgcp_client/mgcp_client_fsm.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/byteswap.h>
+#include <arpa/inet.h>
+#include <osmocom/core/logging.h>
+
+/* Context information, this is attached to the priv pointer of the FSM and
+ * is also handed back when dispatcheing events to the parent FSM. This is
+ * purly intened and not meant to be accessible for the API user */
+struct mgcp_ctx {
+ /* MGCP client instance that is used to interact with the MGW */
+ struct mgcp_client *mgcp;
+
+ /* The ID of the last pending transaction. This is used internally
+ * to cancel the transaction in case of an error */
+ mgcp_trans_id_t mgw_pending_trans;
+
+ /* Flag to mark that there is a pending transaction */
+ bool mgw_trans_pending;
+
+ /* Connection ID which has been assigned by he MGW */
+ char conn_id[MGCP_CONN_ID_LENGTH];
+
+ /* Local RTP connection info, the MGW will send outgoing traffic to the
+ * ip/port specified here. The Address does not have to be choosen right
+ * on the creation of a connection. It can always be modified later by
+ * the user. */
+ struct mgcp_conn_peer conn_peer_local;
+
+ /* Remote RTP connection info, the ip/port specified here is the address
+ * where the MGW expects the RTP data to be sent. This address is
+ * defined by soly by the MGW and can not be influenced by the user. */
+ struct mgcp_conn_peer conn_peer_remote;
+
+ /* The terminate flag is a way to handle cornercase sitations that
+ * might occur when the user runs into an error situation and sends
+ * a DLCX command while the FSM is waiting for a response. In this
+ * case the DLCX command is not executed immediately. Instead the
+ * terminate flag is set. When the response to from the previous
+ * operation is received, we know that there is a DLCX event is
+ * pending. The FSM then generates the EV_DLCX by itsself before
+ * it enters ST_READY to cause the immediate execution of the
+ * DLCX procedure. (If normal operations are executed too fast,
+ * the API functions will return an error. In general, the user
+ * should synchronize using the callback events) */
+ bool terminate;
+
+ /* Event that is sent when the current operation is completed (except
+ * for DLCX, there the specified parent_term_evt is sent instead) */
+ uint32_t parent_evt;
+};
+
+#define S(x) (1 << (x))
+
+#define MGCP_MGW_TIMEOUT 4 /* in seconds */
+#define MGCP_MGW_TIMEOUT_TIMER_NR 1
+
+enum fsm_mgcp_client_states {
+ ST_CRCX,
+ ST_CRCX_RESP,
+ ST_READY,
+ ST_MDCX_RESP,
+ ST_DLCX_RESP,
+};
+
+enum fsm_mgcp_client_evt {
+ EV_CRCX,
+ EV_CRCX_RESP,
+ EV_MDCX,
+ EV_MDCX_RESP,
+ EV_DLCX,
+ EV_DLCX_RESP,
+};
+
+static const struct value_string fsm_mgcp_client_evt_names[] = {
+ OSMO_VALUE_STRING(EV_CRCX),
+ OSMO_VALUE_STRING(EV_CRCX_RESP),
+ OSMO_VALUE_STRING(EV_MDCX),
+ OSMO_VALUE_STRING(EV_MDCX_RESP),
+ OSMO_VALUE_STRING(EV_DLCX),
+ OSMO_VALUE_STRING(EV_DLCX_RESP),
+ {0, NULL}
+};
+
+static struct msgb *make_crcx_msg_bind(struct mgcp_ctx *mgcp_ctx)
+{
+ struct mgcp_msg mgcp_msg;
+
+ mgcp_msg = (struct mgcp_msg) {
+ .verb = MGCP_VERB_CRCX,
+ .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_MODE),
+ .call_id = mgcp_ctx->conn_peer_local.call_id,
+ .conn_mode = MGCP_CONN_LOOPBACK,
+ };
+ osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_local.endpoint, MGCP_ENDPOINT_MAXLEN);
+
+ return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
+}
+
+static struct msgb *make_crcx_msg_bind_connect(struct mgcp_ctx *mgcp_ctx)
+{
+ struct mgcp_msg mgcp_msg;
+
+ mgcp_msg = (struct mgcp_msg) {
+ .verb = MGCP_VERB_CRCX,.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
+ MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP |
+ MGCP_MSG_PRESENCE_AUDIO_PORT),
+ .call_id = mgcp_ctx->conn_peer_local.call_id,
+ .conn_mode = MGCP_CONN_RECV_SEND,
+ .audio_ip = mgcp_ctx->conn_peer_local.addr,
+ .audio_port = mgcp_ctx->conn_peer_local.port,
+ };
+ osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_local.endpoint, MGCP_ENDPOINT_MAXLEN);
+
+ return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
+}
+
+static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
+{
+ struct mgcp_msg mgcp_msg;
+
+ mgcp_msg = (struct mgcp_msg) {
+ .verb = MGCP_VERB_MDCX,
+ .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID |
+ MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT),
+ .call_id = mgcp_ctx->conn_peer_remote.call_id,
+ .conn_id = mgcp_ctx->conn_id,
+ .conn_mode = MGCP_CONN_RECV_SEND,
+ .audio_ip = mgcp_ctx->conn_peer_local.addr,
+ .audio_port = mgcp_ctx->conn_peer_local.port,
+ };
+ osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
+
+ /* Note: We take the endpoint and the call_id from the remote
+ * connection info, because we can be confident that the
+ * information there is valid. For the local info, we explicitly
+ * allow endpoint and call_id to be optional */
+ return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
+}
+
+struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
+{
+ struct mgcp_msg mgcp_msg;
+
+ mgcp_msg = (struct mgcp_msg) {
+ .verb = MGCP_VERB_DLCX,
+ .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID),
+ .call_id = mgcp_ctx->conn_peer_remote.call_id,
+ .conn_id = mgcp_ctx->conn_id,
+ };
+ osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
+
+ return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
+}
+
+static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv);
+
+static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgcp_ctx *mgcp_ctx = data;
+ struct mgcp_client *mgcp;
+ struct msgb *msg;
+ int rc;
+
+ OSMO_ASSERT(mgcp_ctx);
+ mgcp = mgcp_ctx->mgcp;
+ OSMO_ASSERT(mgcp);
+
+ switch (event) {
+ case EV_CRCX:
+ LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: creating connection on MGW endpoint:%s...\n",
+ mgcp_ctx->conn_peer_local.endpoint);
+
+ if (mgcp_ctx->conn_peer_local.port)
+ msg = make_crcx_msg_bind_connect(mgcp_ctx);
+ else
+ msg = make_crcx_msg_bind(mgcp_ctx);
+ OSMO_ASSERT(msg);
+
+ mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
+ mgcp_ctx->mgw_trans_pending = true;
+ rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
+ if (rc < 0) {
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ osmo_fsm_inst_state_chg(fi, ST_CRCX_RESP, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
+static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
+{
+ struct osmo_fsm_inst *fi = priv;
+ struct mgcp_ctx *mgcp_ctx;
+ int rc;
+
+ OSMO_ASSERT(fi);
+ mgcp_ctx = fi->priv;
+ OSMO_ASSERT(mgcp_ctx);
+
+ mgcp_ctx->mgw_trans_pending = false;
+
+ if (r->head.response_code != 200) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "MGW/CRCX: response yields error: %d %s\n", r->head.response_code, r->head.comment);
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ osmo_strlcpy(mgcp_ctx->conn_id, r->head.conn_id, sizeof(mgcp_ctx->conn_id));
+ LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded with CI: %s\n", mgcp_ctx->conn_id);
+
+ rc = mgcp_response_parse_params(r);
+ if (rc) {
+ LOGPFSML(fi, LOGL_ERROR, "MGW/CRCX: Cannot parse CRCX response\n");
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+ LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
+
+ osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
+ mgcp_ctx->conn_peer_remote.port = r->audio_port;
+
+ if (strlen(r->head.endpoint) > 0) {
+ /* If we get an endpoint identifier back from the MGW, take it */
+ osmo_strlcpy(mgcp_ctx->conn_peer_remote.endpoint, r->head.endpoint,
+ sizeof(mgcp_ctx->conn_peer_remote.endpoint));
+ } else if (strstr(mgcp_ctx->conn_peer_local.endpoint, "*") == NULL) {
+ /* If we do not get an endpoint identifier back and the
+ * identifier we used to create the connection is not a
+ * wildcarded one, we take the local endpoint identifier
+ * instead */
+ osmo_strlcpy(mgcp_ctx->conn_peer_remote.endpoint, mgcp_ctx->conn_peer_local.endpoint,
+ sizeof(mgcp_ctx->conn_peer_local.endpoint));
+ } else {
+ LOGPFSML(fi, LOGL_ERROR, "MGW/CRCX: CRCX yielded not suitable endpoint identifier\n");
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ mgcp_ctx->conn_peer_remote.call_id = mgcp_ctx->conn_peer_local.call_id;
+
+ osmo_fsm_inst_dispatch(fi, EV_CRCX_RESP, mgcp_ctx);
+}
+
+static void fsm_crcx_resp_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgcp_ctx *mgcp_ctx = data;
+ OSMO_ASSERT(mgcp_ctx);
+
+ switch (event) {
+ case EV_CRCX_RESP:
+ osmo_fsm_inst_state_chg(fi, ST_READY, 0, 0);
+ if (mgcp_ctx->terminate) {
+ /* Trigger immediate DLCX if DLCX was requested while the FSM was
+ * busy with the previous operation */
+ LOGPFSML(fi, LOGL_ERROR, "MGW/CRCX: FSM was busy while DLCX was requested, executing now...\n");
+ osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
+ } else
+ osmo_fsm_inst_dispatch(fi->proc.parent, mgcp_ctx->parent_evt, &mgcp_ctx->conn_peer_remote);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
+static void mgw_mdcx_resp_cb(struct mgcp_response *r, void *priv);
+static void mgw_dlcx_resp_cb(struct mgcp_response *r, void *priv);
+
+static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgcp_ctx *mgcp_ctx = data;
+ struct msgb *msg;
+ struct mgcp_client *mgcp;
+ uint32_t new_state;
+ int rc;
+
+ OSMO_ASSERT(mgcp_ctx);
+ mgcp = mgcp_ctx->mgcp;
+ OSMO_ASSERT(mgcp);
+
+ switch (event) {
+ case EV_MDCX:
+ msg = make_mdcx_msg(mgcp_ctx);
+ OSMO_ASSERT(msg);
+ rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
+ new_state = ST_MDCX_RESP;
+ break;
+ case EV_DLCX:
+ msg = make_dlcx_msg(mgcp_ctx);
+ OSMO_ASSERT(msg);
+ rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
+ new_state = ST_DLCX_RESP;
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+
+ mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
+ mgcp_ctx->mgw_trans_pending = true;
+
+ if (rc < 0) {
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ osmo_fsm_inst_state_chg(fi, new_state, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR);
+}
+
+static void mgw_mdcx_resp_cb(struct mgcp_response *r, void *priv)
+{
+ struct osmo_fsm_inst *fi = priv;
+ struct mgcp_ctx *mgcp_ctx;
+ int rc;
+
+ OSMO_ASSERT(fi);
+ mgcp_ctx = fi->priv;
+ OSMO_ASSERT(mgcp_ctx);
+
+ mgcp_ctx->mgw_trans_pending = false;
+
+ if (r->head.response_code != 200) {
+ LOGPFSML(fi, LOGL_ERROR, "MGW/MDCX: response yields error: %d %s\n", r->head.response_code,
+ r->head.comment);
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ rc = mgcp_response_parse_params(r);
+ if (rc) {
+ LOGPFSML(fi, LOGL_ERROR, "MGW/MDCX: Cannot parse MDCX response\n");
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+ LOGPFSML(fi, LOGL_DEBUG, "MGW/MDCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
+
+ osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
+ mgcp_ctx->conn_peer_remote.port = r->audio_port;
+
+ osmo_fsm_inst_dispatch(fi, EV_MDCX_RESP, mgcp_ctx);
+}
+
+static void fsm_mdcx_resp_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgcp_ctx *mgcp_ctx = data;
+ OSMO_ASSERT(mgcp_ctx);
+
+ switch (event) {
+ case EV_MDCX_RESP:
+ osmo_fsm_inst_state_chg(fi, ST_READY, 0, 0);
+ if (mgcp_ctx->terminate) {
+ /* Trigger immediate DLCX if DLCX was requested while the FSM was
+ * busy with the previous operation */
+ LOGPFSML(fi, LOGL_ERROR, "MGW/MDCX: FSM was busy while DLCX was requested, executing now...\n");
+ osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
+ } else
+ osmo_fsm_inst_dispatch(fi->proc.parent, mgcp_ctx->parent_evt, &mgcp_ctx->conn_peer_remote);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
+static void mgw_dlcx_resp_cb(struct mgcp_response *r, void *priv)
+{
+ struct osmo_fsm_inst *fi = priv;
+ struct mgcp_ctx *mgcp_ctx;
+
+ OSMO_ASSERT(fi);
+ mgcp_ctx = fi->priv;
+ OSMO_ASSERT(mgcp_ctx);
+
+ mgcp_ctx->mgw_trans_pending = false;
+
+ if (r->head.response_code != 250) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "MGW/DLCX: response yields error: %d %s\n", r->head.response_code, r->head.comment);
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ return;
+ }
+
+ osmo_fsm_inst_dispatch(fi, EV_DLCX_RESP, mgcp_ctx);
+}
+
+static void fsm_dlcx_resp_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct mgcp_ctx *mgcp_ctx = data;
+ OSMO_ASSERT(mgcp_ctx);
+
+ switch (event) {
+ case EV_DLCX_RESP:
+ /* Rub out the connection identifier, since the connection
+ * is no longer present and we will use the connection id
+ * to know in error cases if the connection is still present
+ * or not */
+ memset(mgcp_ctx->conn_id, 0, sizeof(mgcp_ctx->conn_id));
+
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
+static int fsm_timeout_cb(struct osmo_fsm_inst *fi)
+{
+ struct mgcp_ctx *mgcp_ctx = fi->priv;
+ struct mgcp_client *mgcp;
+
+ OSMO_ASSERT(mgcp_ctx);
+ mgcp = mgcp_ctx->mgcp;
+ OSMO_ASSERT(mgcp);
+
+ if (fi->T == MGCP_MGW_TIMEOUT_TIMER_NR) {
+ /* Note: We were unable to communicate with the MGW,
+ * unfortunately there is no meaningful action we can take
+ * now other than giving up. */
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+ } else {
+ /* Note: Ther must not be any unsolicited timers
+ * in this FSM. If so, we have serious problem. */
+ OSMO_ASSERT(false);
+ }
+
+ return 0;
+}
+
+static void fsm_cleanup_cb(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct mgcp_ctx *mgcp_ctx = fi->priv;
+ struct mgcp_client *mgcp;
+ struct msgb *msg;
+
+ OSMO_ASSERT(mgcp_ctx);
+ mgcp = mgcp_ctx->mgcp;
+ OSMO_ASSERT(mgcp);
+
+ /* If there is still a transaction pending, cancel it now. */
+ if (mgcp_ctx->mgw_trans_pending)
+ mgcp_client_cancel(mgcp, mgcp_ctx->mgw_pending_trans);
+
+ /* Should the FSM be terminated while there are still open connections
+ * on the MGW, we send an unconditional DLCX to terminate the
+ * connection. This is not the normal case. The user should always use
+ * mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
+ if (strlen(mgcp_ctx->conn_id)) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "MGW/DLCX: aprupt FSM termination with connections still present, sending unconditional DLCX...\n");
+ msg = make_dlcx_msg(mgcp_ctx);
+ OSMO_ASSERT(msg);
+ mgcp_client_tx(mgcp, msg, NULL, NULL);
+ }
+
+ talloc_free(mgcp_ctx);
+}
+
+static struct osmo_fsm_state fsm_mgcp_client_states[] = {
+
+ /* Initial CRCX state. This state is immediately entered and executed
+ * when the FSM is started. The rationale is that we first have to
+ * create a connectin before we can execute other operations on that
+ * connection. */
+ [ST_CRCX] = {
+ .in_event_mask = S(EV_CRCX),
+ .out_state_mask = S(ST_CRCX_RESP),
+ .name = OSMO_STRINGIFY(ST_CRCX),
+ .action = fsm_crcx_cb,
+ },
+
+ /* Wait for the response to a CRCX operation, check and process the
+ * results, change to ST_READY afterwards. */
+ [ST_CRCX_RESP] = {
+ .in_event_mask = S(EV_CRCX_RESP),
+ .out_state_mask = S(ST_READY),
+ .name = OSMO_STRINGIFY(ST_CRCX_RESP),
+ .action = fsm_crcx_resp_cb,
+ },
+
+ /* In this idle state we wait for further operations (e.g. MDCX) that
+ * can be executed by the user using the API. There is no timeout in
+ * this state. The connection lives on until the user decides to
+ * terminate it (DLCX). */
+ [ST_READY] = {
+ .in_event_mask = S(EV_MDCX) | S(EV_DLCX),
+ .out_state_mask = S(ST_MDCX_RESP) | S(ST_DLCX_RESP),
+ .name = OSMO_STRINGIFY(ST_READY),
+ .action = fsm_ready_cb,
+ },
+
+ /* Wait for the response of a MDCX operation, check and process the
+ * results, change to ST_READY afterwards. */
+ [ST_MDCX_RESP] = {
+ .in_event_mask = S(EV_MDCX_RESP),
+ .out_state_mask = S(ST_READY),
+ .name = OSMO_STRINGIFY(ST_MDCX_RESP),
+ .action = fsm_mdcx_resp_cb,
+ },
+
+ /* Wait for the response of a DLCX operation and terminate the FSM
+ * normally. */
+ [ST_DLCX_RESP] = {
+ .in_event_mask = S(EV_DLCX_RESP),
+ .out_state_mask = 0,
+ .name = OSMO_STRINGIFY(ST_DLCX_RESP),
+ .action = fsm_dlcx_resp_cb,
+ },
+};
+
+static struct osmo_fsm fsm_mgcp_client = {
+ .name = "MGCP_CONN",
+ .states = fsm_mgcp_client_states,
+ .num_states = ARRAY_SIZE(fsm_mgcp_client_states),
+ .timer_cb = fsm_timeout_cb,
+ .cleanup = fsm_cleanup_cb,
+ .event_names = fsm_mgcp_client_evt_names,
+};
+
+/*! allocate FSM, and create a new connection on the MGW.
+ * \param[in] mgcp MGCP client descriptor.
+ * \param[in] mgcpparent_fi Parent FSM instance.
+ * \param[in] parent_term_evt Event to be sent to parent when terminating.
+ * \param[in] parent_evt Event to be sent to parent when operation is done.
+ * \param[in] conn_peer Connection parameters (ip, port...).
+ * \returns newly-allocated, initialized and registered FSM instance, NULL on error. */
+struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi,
+ uint32_t parent_term_evt, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
+{
+ struct mgcp_ctx *mgcp_ctx;
+ static bool fsm_registered = false;
+ struct osmo_fsm_inst *fi;
+ struct in_addr ip_test;
+
+ OSMO_ASSERT(parent_fi);
+ OSMO_ASSERT(mgcp);
+ OSMO_ASSERT(conn_peer);
+
+ /* Check if IP/Port informstaion in conn info makes sense */
+ if (conn_peer->port && inet_aton(conn_peer->addr, &ip_test) == 0)
+ return NULL;
+
+ /* Register the fsm description (if not already done) */
+ if (fsm_registered == false) {
+ osmo_fsm_register(&fsm_mgcp_client);
+ fsm_registered = true;
+ }
+
+ /* Allocate and configure a new fsm instance */
+ fi = osmo_fsm_inst_alloc_child(&fsm_mgcp_client, parent_fi, parent_term_evt);
+ OSMO_ASSERT(fi);
+ mgcp_ctx = talloc_zero(fi, struct mgcp_ctx);
+ OSMO_ASSERT(mgcp_ctx);
+ mgcp_ctx->mgcp = mgcp;
+ mgcp_ctx->parent_evt = parent_evt;
+
+ memcpy(&mgcp_ctx->conn_peer_local, conn_peer, sizeof(mgcp_ctx->conn_peer_local));
+ fi->priv = mgcp_ctx;
+
+ /* start state machine */
+ OSMO_ASSERT(fi->state == ST_CRCX);
+ osmo_fsm_inst_dispatch(fi, EV_CRCX, mgcp_ctx);
+
+ return fi;
+}
+
+/*! modify an existing connection on the MGW.
+ * \param[in] fi FSM instance.
+ * \param[in] parent_evt Event to be sent to parent when operation is done.
+ * \param[in] conn_peer New connection information (ip, port...).
+ * \returns 0 on success, -EINVAL on error. */
+int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
+{
+ OSMO_ASSERT(fi);
+ struct mgcp_ctx *mgcp_ctx = fi->priv;
+ struct in_addr ip_test;
+
+ OSMO_ASSERT(mgcp_ctx);
+ OSMO_ASSERT(conn_peer);
+
+ /* The user must not issue an MDCX before the CRCX has completed,
+ * if this happens, it means that the parent FSM has overhead the
+ * parent_evt (mandatory!) and executed the MDCX without even
+ * waiting for the results. Another reason could be that the
+ * parent FSM got messed up */
+ OSMO_ASSERT(fi->state != ST_CRCX_RESP);
+
+ /* If the user tries to issue an MDCX while an DLCX operation is
+ * pending, there must be a serious problem with the paren FSM.
+ * Eeither the parent_term_evt (mandatory!) has been overheard,
+ * or the parant FSM got messed so badly that it still assumes
+ * a live connection although it as killed it. */
+ OSMO_ASSERT(fi->state != ST_DLCX_RESP);
+
+ /* Check if IP/Port parameters make sense */
+ if (conn_peer->port == 0)
+ return -EINVAL;
+ if (inet_aton(conn_peer->addr, &ip_test) == 0)
+ return -EINVAL;
+
+ /*! The user may supply an endpoint identifier in conn_peer. The
+ * identifier is then checked. This check is optional. Later steps do
+ * not depend on the endpoint identifier supplied here because it is
+ * already implicitly known from the CRCX phase. */
+ if (strlen(conn_peer->endpoint) && strcmp(conn_peer->endpoint, mgcp_ctx->conn_peer_remote.endpoint))
+ return -EINVAL;
+
+ /*! Note: The call-id is implicitly known from the previous CRCX and
+ * will not be checked even when it is set in conn_peer. */
+
+ mgcp_ctx->parent_evt = parent_evt;
+ memcpy(&mgcp_ctx->conn_peer_local, conn_peer, sizeof(mgcp_ctx->conn_peer_local));
+ osmo_fsm_inst_dispatch(fi, EV_MDCX, mgcp_ctx);
+ return 0;
+}
+
+/*! delete existing connection on the MGW, destroy FSM afterwards.
+ * \param[in] fi FSM instance. */
+void mgcp_conn_delete(struct osmo_fsm_inst *fi)
+{
+ OSMO_ASSERT(fi);
+ struct mgcp_ctx *mgcp_ctx = fi->priv;
+
+ OSMO_ASSERT(mgcp_ctx);
+
+ /* Unlink FSM from parent */
+ osmo_fsm_inst_unlink_parent(fi, NULL);
+
+ /* An error situation where the parent FSM must be killed immediately
+ * may lead into a situation where the DLCX can not be executed right
+ * at that moment because the FSM is still busy with another operation.
+ * In those cases we postpone the DLCX so that the FSM and the
+ * connections on the MGW get cleaned up gracefully. */
+ if (fi->state != ST_READY) {
+ LOGPFSML(fi, LOGL_ERROR, "MGW: operation still pending, DLCX will be postponed.\n");
+ mgcp_ctx->terminate = true;
+ return;
+ }
+ osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
+}
diff --git a/src/libosmo-mgcp-client/mgcp_client_vty.c b/src/libosmo-mgcp-client/mgcp_client_vty.c
index f8129c0..10d078a 100644
--- a/src/libosmo-mgcp-client/mgcp_client_vty.c
+++ b/src/libosmo-mgcp-client/mgcp_client_vty.c
@@ -6,16 +6,16 @@
* 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
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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.
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
+ * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -25,6 +25,7 @@
#include <talloc.h>
#include <osmocom/vty/command.h>
+#include <osmocom/vty/misc.h>
#include <osmocom/core/utils.h>
#include <osmocom/mgcp_client/mgcp_client.h>
@@ -203,4 +204,6 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
install_element(node, &cfg_mgcpgw_remote_port_cmd);
install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
install_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
+
+ osmo_fsm_vty_add_cmds();
}
diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am
index fce0e1b..a98c391 100644
--- a/src/libosmo-mgcp/Makefile.am
+++ b/src/libosmo-mgcp/Makefile.am
@@ -7,6 +7,7 @@ AM_CPPFLAGS = \
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
@@ -14,24 +15,21 @@ AM_CFLAGS = \
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)
-# 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_LIBVERSION=1:0:0
-
-lib_LTLIBRARIES = \
- libosmo-mgcp.la \
+noinst_LIBRARIES = \
+ libosmo-mgcp.a \
$(NULL)
noinst_HEADERS = \
g711common.h \
$(NULL)
-libosmo_mgcp_la_SOURCES = \
+libosmo_mgcp_a_SOURCES = \
mgcp_protocol.c \
mgcp_network.c \
mgcp_vty.c \
@@ -40,7 +38,5 @@ libosmo_mgcp_la_SOURCES = \
mgcp_msg.c \
mgcp_conn.c \
mgcp_stat.c \
- mgcp_ep.c \
+ mgcp_endp.c \
$(NULL)
-
-libosmo_mgcp_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_LIBVERSION)
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index e0eec63..998dbc5 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -24,10 +24,51 @@
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
-#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/mgcp/mgcp_endp.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <ctype.h>
+
+/* Allocate a new connection identifier. According to RFC3435, they must
+ * be unique only within the scope of the endpoint. (Caller must provide
+ * memory for id) */
+static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
+{
+ int i;
+ int k;
+ int rc;
+ uint8_t id_bin[16];
+ char *id_hex;
+
+ /* Generate a connection id that is unique for the current endpoint.
+ * Technically a counter would be sufficient, but in order to
+ * be able to find a specific connection in large logfiles and to
+ * prevent unintentional connections we assign the connection
+ * identifiers randomly from a reasonable large number space */
+ for (i = 0; i < 32; i++) {
+ rc = osmo_get_rand_id(id_bin, sizeof(id_bin));
+ if (rc < 0)
+ return rc;
+
+ id_hex = osmo_hexdump_nospc(id_bin, sizeof(id_bin));
+ for (k = 0; k < strlen(id_hex); k++)
+ id_hex[k] = toupper(id_hex[k]);
+
+ /* ensure that the generated conn_id is unique
+ * for this endpoint */
+ if (!mgcp_conn_get_rtp(endp, id_hex)) {
+ osmo_strlcpy(id, id_hex, MGCP_CONN_ID_LENGTH);
+ return 0;
+ }
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x, unable to generate a unique connectionIdentifier\n",
+ ENDPOINT_NUMBER(endp));
+
+ return -1;
+}
/* Reset codec state and free memory */
-static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
+static void mgcp_rtp_codec_init(struct mgcp_rtp_codec *codec)
{
codec->payload_type = -1;
codec->subtype_name = NULL;
@@ -42,22 +83,20 @@ static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
talloc_free(codec->audio_name);
}
-/* Reset states, free memory, set defaults and reset codec state */
-static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn)
+/* Initialize rtp connection struct with default values */
+static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
{
- struct mgcp_rtp_end *end = &conn->end;
+ struct mgcp_rtp_end *end = &conn_rtp->end;
- conn->type = MGCP_RTP_DEFAULT;
- conn->osmux.allocated_cid = -1;
+ conn_rtp->type = MGCP_RTP_DEFAULT;
+ conn_rtp->osmux.allocated_cid = -1;
+
+ /* backpointer to the generic part of the connection */
+ conn->u.rtp.conn = conn;
end->rtp.fd = -1;
end->rtcp.fd = -1;
- end->local_port = 0;
- end->packets_rx = 0;
- end->octets_rx = 0;
- end->packets_tx = 0;
- end->octets_tx = 0;
- end->dropped_packets = 0;
+ memset(&end->stats, 0, sizeof(end->stats));
end->rtp_port = end->rtcp_port = 0;
talloc_free(end->fmtp_extra);
end->fmtp_extra = NULL;
@@ -67,8 +106,16 @@ static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn)
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = 0;
- mgcp_rtp_codec_reset(&end->codec);
- mgcp_rtp_codec_reset(&end->alt_codec);
+ mgcp_rtp_codec_init(&end->codec);
+ mgcp_rtp_codec_init(&end->alt_codec);
+}
+
+/* Cleanup rtp connection struct */
+static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
+{
+ osmux_disable_conn(conn_rtp);
+ osmux_release_cid(conn_rtp);
+ mgcp_free_rtp_port(&conn_rtp->end);
}
/*! allocate a new connection list entry.
@@ -78,22 +125,15 @@ static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn)
* \param[in] type connection type (e.g. MGCP_CONN_TYPE_RTP)
* \returns pointer to allocated connection, NULL on error */
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
- uint32_t id, enum mgcp_conn_type type,
- char *name)
+ enum mgcp_conn_type type, char *name)
{
struct mgcp_conn *conn;
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
- OSMO_ASSERT(strlen(name) < sizeof(conn->name));
+ int rc;
/* Do not allow more then two connections */
if (llist_count(&endp->conns) >= endp->type->max_conns)
return NULL;
- /* Prevent duplicate connection IDs */
- if (mgcp_conn_get(endp, id))
- return NULL;
-
/* Create new connection and add it to the list */
conn = talloc_zero(ctx, struct mgcp_conn);
if (!conn)
@@ -102,13 +142,16 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
conn->type = type;
conn->mode = MGCP_CONN_NONE;
conn->mode_orig = MGCP_CONN_NONE;
- conn->id = id;
- conn->u.rtp.conn = conn;
- strcpy(conn->name, name);
+ osmo_strlcpy(conn->name, name, sizeof(conn->name));
+ rc = mgcp_alloc_id(endp, conn->id);
+ if (rc < 0) {
+ talloc_free(conn);
+ return NULL;
+ }
switch (type) {
case MGCP_CONN_TYPE_RTP:
- mgcp_rtp_conn_reset(&conn->u.rtp);
+ mgcp_rtp_conn_init(&conn->u.rtp, conn);
break;
default:
/* NOTE: This should never be called with an
@@ -126,15 +169,12 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
-struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, uint32_t id)
+struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
{
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
-
struct mgcp_conn *conn;
llist_for_each_entry(conn, &endp->conns, entry) {
- if (conn->id == id)
+ if (strncmp(conn->id, id, sizeof(conn->id)) == 0)
return conn;
}
@@ -145,11 +185,9 @@ struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, uint32_t id)
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
-struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, uint32_t id)
+struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
+ const char *id)
{
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
-
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
@@ -165,22 +203,23 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, uint32_t id)
/*! free a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection */
-void mgcp_conn_free(struct mgcp_endpoint *endp, uint32_t id)
+void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
{
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
-
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
if (!conn)
return;
+ /* Run endpoint cleanup action. By this we inform the endpoint about
+ * the removal of the connection and allow it to clean up its inner
+ * state accordingly */
+ if (endp->type->cleanup_cb)
+ endp->type->cleanup_cb(endp, conn);
+
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
- osmux_disable_conn(&conn->u.rtp);
- osmux_release_cid(&conn->u.rtp);
- mgcp_free_rtp_port(&conn->u.rtp.end);
+ mgcp_rtp_conn_cleanup(&conn->u.rtp);
break;
default:
/* NOTE: This should never be called with an
@@ -197,9 +236,6 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, uint32_t id)
* \param[in] endp associated endpoint */
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
{
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
-
struct mgcp_conn *conn;
if (llist_empty(&endp->conns))
@@ -216,9 +252,6 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
* \param[in] endp associated endpoint */
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
{
- OSMO_ASSERT(endp);
- OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
-
struct mgcp_conn *conn;
struct mgcp_conn *conn_tmp;
@@ -230,12 +263,12 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp)
return;
}
-/*! dump basic connection information to human readble string.
+/*! dump basic connection information to human readable string.
* \param[in] conn to dump
- * \returns human readble string */
+ * \returns human readable string */
char *mgcp_conn_dump(struct mgcp_conn *conn)
{
- static char str[256];
+ static char str[sizeof(conn->name)+sizeof(conn->id)+256];
if (!conn) {
snprintf(str, sizeof(str), "(null connection)");
@@ -245,7 +278,7 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
/* Dump RTP connection */
- snprintf(str, sizeof(str), "(%s/rtp, id:%u, ip:%s, "
+ snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
"rtp:%u rtcp:%u)",
conn->name,
conn->id,
diff --git a/src/libosmo-mgcp/mgcp_ep.c b/src/libosmo-mgcp/mgcp_endp.c
index 72ca691..fa2dd28 100644
--- a/src/libosmo-mgcp/mgcp_ep.c
+++ b/src/libosmo-mgcp/mgcp_endp.c
@@ -21,12 +21,36 @@
*
*/
-#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/mgcp/mgcp_internal.h>
+#include <osmocom/mgcp/mgcp_endp.h>
/* Endpoint typeset definition */
const struct mgcp_endpoint_typeset ep_typeset = {
/* Specify endpoint properties for RTP endpoint */
.rtp.max_conns = 2,
- .rtp.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb
+ .rtp.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
+ .rtp.cleanup_cb = mgcp_cleanup_rtp_bridge_cb
};
+
+/*! release endpoint, all open connections are closed.
+ * \param[in] endp endpoint to release */
+void mgcp_endp_release(struct mgcp_endpoint *endp)
+{
+ LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint:0x%x\n",
+ ENDPOINT_NUMBER(endp));
+
+ /* Normally this function should only be called when
+ * all connections have been removed already. In case
+ * that there are still connections open (e.g. when
+ * RSIP is executed), free them all at once. */
+ mgcp_conn_free_all(endp);
+
+ /* Reset endpoint parameters and states */
+ talloc_free(endp->callid);
+ endp->callid = NULL;
+ talloc_free(endp->local_options.string);
+ endp->local_options.string = NULL;
+ talloc_free(endp->local_options.codec);
+ endp->local_options.codec = NULL;
+ endp->wildcarded_req = false;
+}
diff --git a/src/libosmo-mgcp/mgcp_msg.c b/src/libosmo-mgcp/mgcp_msg.c
index d686bca..8d22cc5 100644
--- a/src/libosmo-mgcp/mgcp_msg.c
+++ b/src/libosmo-mgcp/mgcp_msg.c
@@ -28,6 +28,7 @@
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_msg.h>
#include <osmocom/mgcp/mgcp_conn.h>
+#include <osmocom/mgcp/mgcp_endp.h>
/*! Display an mgcp message on the log output.
* \param[in] message mgcp message string
@@ -82,7 +83,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
if (!mode) {
LOGP(DLMGCP, LOGL_ERROR,
- "endpoint:%x missing connection mode\n",
+ "endpoint:0x%x missing connection mode\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -101,7 +102,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
conn->mode = MGCP_CONN_LOOPBACK;
else {
LOGP(DLMGCP, LOGL_ERROR,
- "endpoint:%x unknown connection mode: '%s'\n",
+ "endpoint:0x%x unknown connection mode: '%s'\n",
ENDPOINT_NUMBER(endp), mode);
ret = -1;
}
@@ -113,16 +114,16 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
}
LOGP(DLMGCP, LOGL_DEBUG,
- "endpoint:%x conn:%s\n",
+ "endpoint:0x%x conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn));
LOGP(DLMGCP, LOGL_DEBUG,
- "endpoint:%x connection mode '%s' %d\n",
+ "endpoint:0x%x connection mode '%s' %d\n",
ENDPOINT_NUMBER(endp), mode, conn->mode);
/* Special handling für RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
- LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x output_enabled %d\n",
+ LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x output_enabled %d\n",
ENDPOINT_NUMBER(endp), conn->u.rtp.end.output_enabled);
}
@@ -142,6 +143,7 @@ static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
char *rest = NULL;
struct mgcp_trunk_config *tcfg;
int trunk, endp;
+ struct mgcp_endpoint *endp_ptr;
trunk = strtoul(mgcp + 6, &rest, 10);
if (rest == NULL || rest[0] != '/' || trunk < 1) {
@@ -178,25 +180,112 @@ static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
return NULL;
}
- return &tcfg->endpoints[endp];
+ endp_ptr = &tcfg->endpoints[endp];
+ endp_ptr->wildcarded_req = false;
+ return endp_ptr;
+}
+
+/* Find an endpoint that is not in use. Do this by going through the endpoint
+ * array, check the callid. A callid nullpointer indicates that the endpoint
+ * is free */
+static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
+ unsigned int number_endpoints)
+{
+ struct mgcp_endpoint *endp;
+ unsigned int i;
+
+ for (i = 0; i < number_endpoints; i++) {
+ if (endpoints[i].callid == NULL) {
+ endp = &endpoints[i];
+ LOGP(DLMGCP, LOGL_DEBUG,
+ "endpoint:0x%x found free endpoint\n",
+ ENDPOINT_NUMBER(endp));
+ endp->wildcarded_req = true;
+ return endp;
+ }
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR, "Not able to find a free endpoint\n");
+ return NULL;
+}
+
+/* Check if the domain name, which is supplied with the endpoint name
+ * matches the configuration. */
+static int check_domain_name(struct mgcp_config *cfg, const char *mgcp)
+{
+ char *domain_to_check;
+
+ domain_to_check = strstr(mgcp, "@");
+ if (!domain_to_check)
+ return -EINVAL;
+
+ if (strcmp(domain_to_check+1, cfg->domain) != 0)
+ return -EINVAL;
+
+ return 0;
}
/* Search the endpoint pool for the endpoint that had been selected via the
* MGCP message (helper function for mgcp_analyze_header()) */
static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg,
- const char *mgcp)
+ const char *mgcp,
+ int *cause)
{
char *endptr = NULL;
unsigned int gw = INT_MAX;
+ const char *endpoint_number_str;
+ struct mgcp_endpoint *endp;
+
+ *cause = 0;
+
+ /* Check if the domainname in the request is correct */
+ if (check_domain_name(cfg, mgcp)) {
+ LOGP(DLMGCP, LOGL_ERROR, "Wrong domain name '%s'\n", mgcp);
+ return NULL;
+ }
- if (strncmp(mgcp, "ds/e1", 5) == 0)
- return find_e1_endpoint(cfg, mgcp);
+ /* Check if the E1 trunk is requested */
+ if (strncmp(mgcp, "ds/e1", 5) == 0) {
+ endp = find_e1_endpoint(cfg, mgcp);
+ if (!endp)
+ *cause = -500;
+ return endp;
+ }
+
+ /* Check if the virtual trunk is addressed (new, correct way with prefix) */
+ if (strncmp
+ (mgcp, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
+ strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK)) == 0) {
+ endpoint_number_str =
+ mgcp + strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
+ if (endpoint_number_str[0] == '*') {
+ endp = find_free_endpoint(cfg->trunk.endpoints,
+ cfg->trunk.number_endpoints);
+ if (!endp)
+ *cause = -403;
+ return endp;
+ }
+ gw = strtoul(endpoint_number_str, &endptr, 16);
+ if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
+ endp = &cfg->trunk.endpoints[gw];
+ endp->wildcarded_req = false;
+ return endp;
+ }
+ }
+ /* Deprecated method without prefix */
+ LOGP(DLMGCP, LOGL_NOTICE,
+ "Addressing virtual trunk without prefix (deprecated), please use %s: '%s'\n",
+ MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, mgcp);
gw = strtoul(mgcp, &endptr, 16);
- if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
- return &cfg->trunk.endpoints[gw];
+ if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
+ endp = &cfg->trunk.endpoints[gw];
+ endp->wildcarded_req = false;
+ return endp;
+ }
LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
+ *cause = -500;
return NULL;
}
@@ -209,6 +298,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
{
int i = 0;
char *elem, *save = NULL;
+ int cause;
/*! This function will parse the header part of the received
* MGCP message. The parsing results are stored in pdata.
@@ -226,25 +316,25 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
pdata->trans = elem;
break;
case 1:
- pdata->endp = find_endpoint(pdata->cfg, elem);
+ pdata->endp = find_endpoint(pdata->cfg, elem, &cause);
if (!pdata->endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Unable to find Endpoint `%s'\n", elem);
- return -1;
+ return cause;
}
break;
case 2:
if (strcmp("MGCP", elem)) {
LOGP(DLMGCP, LOGL_ERROR,
"MGCP header parsing error\n");
- return -1;
+ return -510;
}
break;
case 3:
if (strcmp("1.0", elem)) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
"not supported\n", elem);
- return -1;
+ return -528;
}
break;
}
@@ -255,7 +345,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
pdata->trans = "000000";
pdata->endp = NULL;
- return -1;
+ return -510;
}
return 0;
@@ -318,7 +408,7 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
if (strcmp(endp->callid, callid) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "endpoint:%x CallIDs does not match '%s' != '%s'\n",
+ "endpoint:0x%x CallIDs does not match '%s' != '%s'\n",
ENDPOINT_NUMBER(endp), endp->callid, callid);
return -1;
}
@@ -330,21 +420,39 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
* \param[in] endp pointer to endpoint
* \param{in] connection id to verify
* \returns 1 when connection id seems plausible, 0 on error */
-int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *ci)
+int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
{
- uint32_t id;
+ /* Check for null identifiers */
+ if (!conn_id) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "endpoint:0x%x invalid ConnectionIdentifier (missing)\n",
+ ENDPOINT_NUMBER(endp));
+ return -1;
+ }
- if (!endp)
+ /* Check for empty connection identifiers */
+ if (strlen(conn_id) == 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "endpoint:0x%x invalid ConnectionIdentifier (empty)\n",
+ ENDPOINT_NUMBER(endp));
return -1;
+ }
- id = strtoul(ci, NULL, 10);
+ /* Check for over long connection identifiers */
+ if (strlen(conn_id) > MGCP_CONN_ID_LENGTH) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "endpoint:0x%x invalid ConnectionIdentifier (too long) 0x%s\n",
+ ENDPOINT_NUMBER(endp), conn_id);
+ return -1;
+ }
- if (mgcp_conn_get(endp, id))
+ /* Check if connection exists */
+ if (mgcp_conn_get(endp, conn_id))
return 0;
LOGP(DLMGCP, LOGL_ERROR,
- "endpoint:%x No connection found under ConnectionIdentifier %u\n",
- ENDPOINT_NUMBER(endp), id);
+ "endpoint:0x%x no connection found under ConnectionIdentifier 0x%s\n",
+ ENDPOINT_NUMBER(endp), conn_id);
return -1;
}
@@ -386,20 +494,3 @@ char *mgcp_strline(char *str, char **saveptr)
return result;
}
-
-/*! Parse CI from a given string.
- * \param[out] caller provided memory to store the result
- * \param{in] string containing the connection id
- * \returns 0 on success, -1 on error */
-int mgcp_parse_ci(uint32_t *conn_id, const char *ci)
-{
-
- OSMO_ASSERT(conn_id);
-
- if (!ci)
- return -1;
-
- *conn_id = strtoul(ci, NULL, 10);
-
- return 0;
-}
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index d51b829..6923b97 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -27,7 +27,6 @@
#include <errno.h>
#include <time.h>
#include <limits.h>
-#include <sys/socket.h>
#include <arpa/inet.h>
#include <osmocom/core/msgb.h>
@@ -40,7 +39,7 @@
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
-#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/debug.h>
#define RTP_SEQ_MOD (1 << 16)
@@ -73,11 +72,11 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
rc = osmo_sock_local_ip(addr, inet_ntoa(conn->end.addr));
if (rc < 0)
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x CI:%i local interface auto detection failed, using configured addresses...\n",
+ "endpoint:0x%x CI:%s local interface auto detection failed, using configured addresses...\n",
ENDPOINT_NUMBER(endp), conn->conn->id);
else {
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x CI:%i selected local rtp bind ip %s by probing using remote ip %s\n",
+ "endpoint:0x%x CI:%s selected local rtp bind ip %s by probing using remote ip %s\n",
ENDPOINT_NUMBER(endp), conn->conn->id, addr,
inet_ntoa(conn->end.addr));
return;
@@ -88,17 +87,17 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
if (endp->cfg->net_ports.bind_addr) {
/* Check there is a bind IP for the RTP traffic configured,
* if so, use that IP-Address */
- strncpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
+ osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x CI:%i using configured rtp bind ip as local bind ip %s\n",
+ "endpoint:0x%x CI:%s using configured rtp bind ip as local bind ip %s\n",
ENDPOINT_NUMBER(endp), conn->conn->id, addr);
} else {
/* No specific bind IP is configured for the RTP traffic, so
* assume the IP where we listen for incoming MGCP messages
* as bind IP */
- strncpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
+ osmo_strlcpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x CI:%i using mgcp bind ip as local rtp bind ip: %s\n",
+ "endpoint:0x%x CI:%s using mgcp bind ip as local rtp bind ip: %s\n",
ENDPOINT_NUMBER(endp), conn->conn->id, addr);
}
}
@@ -162,8 +161,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
OSMO_ASSERT(conn);
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x sending dummy packet...\n", ENDPOINT_NUMBER(endp));
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x conn:%s\n",
+ "endpoint:0x%x sending dummy packet...\n", ENDPOINT_NUMBER(endp));
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
@@ -184,7 +183,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
failed:
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x Failed to send dummy %s packet.\n",
+ "endpoint:0x%x Failed to send dummy %s packet.\n",
ENDPOINT_NUMBER(endp), was_rtcp ? "RTCP" : "RTP");
return -1;
@@ -231,7 +230,7 @@ static int check_rtp_timestamp(struct mgcp_endpoint *endp,
"on 0x%x SSRC: %u timestamp: %u "
"from %s:%d\n",
text, seq,
- state->timestamp_offset, state->seq_offset,
+ state->patch.timestamp_offset, state->patch.seq_offset,
ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -325,15 +324,15 @@ static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
timestamp_offset = out_timestamp - in_timestamp;
- if (state->timestamp_offset != timestamp_offset) {
- state->timestamp_offset = timestamp_offset;
+ if (state->patch.timestamp_offset != timestamp_offset) {
+ state->patch.timestamp_offset = timestamp_offset;
LOGP(DRTP, LOGL_NOTICE,
"Timestamp offset change on 0x%x SSRC: %u "
"SeqNo delta: %d, TS offset: %d, "
"from %s:%d\n",
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- delta_seq, state->timestamp_offset,
+ delta_seq, state->patch.timestamp_offset,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -354,11 +353,11 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
/* Align according to: T + Toffs - Tlast = k * Tptime */
ts_error = ts_alignment_error(&state->out_stream, ptime,
- timestamp + state->timestamp_offset);
+ timestamp + state->patch.timestamp_offset);
/* If there is an alignment error, we have to compensate it */
if (ts_error) {
- state->timestamp_offset += ptime - ts_error;
+ state->patch.timestamp_offset += ptime - ts_error;
LOGP(DRTP, LOGL_NOTICE,
"Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
@@ -366,16 +365,16 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
"from %s:%d\n",
ts_error,
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->timestamp_offset, inet_ntoa(addr->sin_addr),
+ state->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
}
/* Check we really managed to compensate the timestamp
* offset. There should not be any remaining error, failing
- * here would point to a serous problem with the alingnment
- * error computation fuction */
+ * here would point to a serous problem with the alignment
+ * error computation function */
ts_check = ts_alignment_error(&state->out_stream, ptime,
- timestamp + state->timestamp_offset);
+ timestamp + state->patch.timestamp_offset);
OSMO_ASSERT(ts_check == 0);
/* Return alignment error before compensation */
@@ -387,13 +386,13 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
* \param[in] destination RTP end
* \param[in,out] pointer to buffer with voice data
* \param[in] voice data length
- * \param[in] maxmimum size of caller provided voice data buffer
+ * \param[in] maximum size of caller provided voice data buffer
* \returns ignores input parameters, return always 0 */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size)
{
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x transcoding disabled\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
ENDPOINT_NUMBER(endp));
return 0;
}
@@ -407,7 +406,7 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct mgcp_rtp_end *src_end)
{
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x transcoding disabled\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
ENDPOINT_NUMBER(endp));
return 0;
}
@@ -419,7 +418,7 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn)
{
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x conn:%s using format defaults\n",
+ "endpoint:0x%x conn:%s using format defaults\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
*payload_type = conn->end.codec.payload_type;
@@ -434,14 +433,14 @@ void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
int32_t d;
/* initialize or re-initialize */
- if (!state->stats_initialized || state->stats_ssrc != ssrc) {
- state->stats_initialized = 1;
- state->stats_base_seq = seq;
- state->stats_max_seq = seq - 1;
- state->stats_ssrc = ssrc;
- state->stats_jitter = 0;
- state->stats_transit = transit;
- state->stats_cycles = 0;
+ if (!state->stats.initialized || state->stats.ssrc != ssrc) {
+ state->stats.initialized = 1;
+ state->stats.base_seq = seq;
+ state->stats.max_seq = seq - 1;
+ state->stats.ssrc = ssrc;
+ state->stats.jitter = 0;
+ state->stats.transit = transit;
+ state->stats.cycles = 0;
} else {
uint16_t udelta;
@@ -452,10 +451,10 @@ void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
* It can't wrap during the initialization so let's
* skip it here. The Appendix A probably doesn't have
* this issue because of the probation. */
- udelta = seq - state->stats_max_seq;
+ udelta = seq - state->stats.max_seq;
if (udelta < RTP_MAX_DROPOUT) {
- if (seq < state->stats_max_seq)
- state->stats_cycles += RTP_SEQ_MOD;
+ if (seq < state->stats.max_seq)
+ state->stats.cycles += RTP_SEQ_MOD;
} else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
LOGP(DRTP, LOGL_NOTICE,
"RTP seqno made a very large jump on 0x%x delta: %u\n",
@@ -467,12 +466,12 @@ void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
* taken closer to the read function. This was taken from the
* Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
* resolution. */
- d = transit - state->stats_transit;
- state->stats_transit = transit;
+ d = transit - state->stats.transit;
+ state->stats.transit = transit;
if (d < 0)
d = -d;
- state->stats_jitter += d - ((state->stats_jitter + 8) >> 4);
- state->stats_max_seq = seq;
+ state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
+ state->stats.max_seq = seq;
}
/* The RFC 3550 Appendix A assumes there are multiple sources but
@@ -508,7 +507,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
if (!state->initialized) {
state->initialized = 1;
state->in_stream.last_seq = seq - 1;
- state->in_stream.ssrc = state->orig_ssrc = ssrc;
+ state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
state->in_stream.last_tsdelta = 0;
state->packet_duration =
mgcp_rtp_packet_duration(endp, rtp_end);
@@ -516,23 +515,23 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
state->out_stream.last_timestamp = timestamp;
state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
LOGP(DRTP, LOGL_INFO,
- "endpoint:%x initializing stream, SSRC: %u timestamp: %u "
+ "endpoint:0x%x initializing stream, SSRC: %u timestamp: %u "
"pkt-duration: %d, from %s:%d\n",
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->seq_offset, state->packet_duration,
+ state->patch.seq_offset, state->packet_duration,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
if (state->packet_duration == 0) {
state->packet_duration =
rtp_end->codec.rate * 20 / 1000;
LOGP(DRTP, LOGL_NOTICE,
- "endpoint:%x fixed packet duration is not available, "
+ "endpoint:0x%x fixed packet duration is not available, "
"using fixed 20ms instead: %d from %s:%d\n",
ENDPOINT_NUMBER(endp), state->packet_duration,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
} else if (state->in_stream.ssrc != ssrc) {
LOGP(DRTP, LOGL_NOTICE,
- "endpoint:%x SSRC changed: %u -> %u "
+ "endpoint:0x%x SSRC changed: %u -> %u "
"from %s:%d\n",
ENDPOINT_NUMBER(endp),
state->in_stream.ssrc, rtp_hdr->ssrc,
@@ -543,7 +542,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
int16_t delta_seq;
/* Always increment seqno by 1 */
- state->seq_offset =
+ state->patch.seq_offset =
(state->out_stream.last_seq + 1) - seq;
/* Estimate number of packets that would have been sent */
@@ -555,17 +554,17 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
delta_seq, timestamp);
- state->patch_ssrc = 1;
- ssrc = state->orig_ssrc;
+ state->patch.patch_ssrc = 1;
+ ssrc = state->patch.orig_ssrc;
if (rtp_end->force_constant_ssrc != -1)
rtp_end->force_constant_ssrc -= 1;
LOGP(DRTP, LOGL_NOTICE,
- "endpoint:%x SSRC patching enabled, SSRC: %u "
+ "endpoint:0x%x SSRC patching enabled, SSRC: %u "
"SeqNo offset: %d, TS offset: %d "
"from %s:%d\n",
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
- state->seq_offset, state->timestamp_offset,
+ state->patch.seq_offset, state->patch.timestamp_offset,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -576,8 +575,8 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
addr, seq, timestamp, "input",
&state->in_stream.last_tsdelta);
- if (state->patch_ssrc)
- ssrc = state->orig_ssrc;
+ if (state->patch.patch_ssrc)
+ ssrc = state->patch.orig_ssrc;
}
/* Save before patching */
@@ -592,15 +591,15 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
timestamp);
/* Store the updated SSRC back to the packet */
- if (state->patch_ssrc)
+ if (state->patch.patch_ssrc)
rtp_hdr->ssrc = htonl(ssrc);
/* Apply the offset and store it back to the packet.
* This won't change anything if the offset is 0, so the conditional is
* omitted. */
- seq += state->seq_offset;
+ seq += state->patch.seq_offset;
rtp_hdr->sequence = htons(seq);
- timestamp += state->timestamp_offset;
+ timestamp += state->patch.timestamp_offset;
rtp_hdr->timestamp = htonl(timestamp);
/* Check again, whether the timestamps are still valid */
@@ -619,7 +618,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
#if 0
DEBUGP(DRTP,
- "endpoint:%x payload hdr payload %u -> endp payload %u\n",
+ "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
rtp_hdr->payload_type = payload;
#endif
@@ -670,16 +669,16 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
if (is_rtp) {
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x delivering RTP packet...\n",
+ "endpoint:0x%x delivering RTP packet...\n",
ENDPOINT_NUMBER(endp));
} else {
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x delivering RTCP packet...\n",
+ "endpoint:0x%x delivering RTCP packet...\n",
ENDPOINT_NUMBER(endp));
}
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x loop:%d, mode:%d ",
+ "endpoint:0x%x loop:%d, mode:%d ",
ENDPOINT_NUMBER(endp), tcfg->audio_loop, conn_src->conn->mode);
if (conn_src->conn->mode == MGCP_CONN_LOOPBACK)
LOGPC(DRTP, LOGL_DEBUG, "(loopback)\n");
@@ -693,9 +692,9 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
dest_name = conn_dst->conn->name;
if (!rtp_end->output_enabled) {
- rtp_end->dropped_packets += 1;
+ rtp_end->stats.dropped_packets += 1;
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x output disabled, drop to %s %s "
+ "endpoint:0x%x output disabled, drop to %s %s "
"rtp_port:%u rtcp_port:%u\n",
ENDPOINT_NUMBER(endp),
dest_name,
@@ -718,7 +717,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
mgcp_patch_and_count(endp, rtp_state, rtp_end,
addr, buf, buflen);
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x process/send to %s %s "
+ "endpoint:0x%x process/send to %s %s "
"rtp_port:%u rtcp_port:%u\n",
ENDPOINT_NUMBER(endp), dest_name,
inet_ntoa(rtp_end->addr), ntohs(rtp_end->rtp_port),
@@ -748,8 +747,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
if (len <= 0)
return len;
- conn_dst->end.packets_tx += 1;
- conn_dst->end.octets_tx += len;
+ conn_dst->end.stats.packets_tx += 1;
+ conn_dst->end.stats.octets_tx += len;
nbytes += len;
buflen = cont;
@@ -757,7 +756,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
return nbytes;
} else if (!tcfg->omit_rtcp) {
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x send to %s %s rtp_port:%u rtcp_port:%u\n",
+ "endpoint:0x%x send to %s %s rtp_port:%u rtcp_port:%u\n",
ENDPOINT_NUMBER(endp),
dest_name,
inet_ntoa(rtp_end->addr),
@@ -768,8 +767,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
&rtp_end->addr,
rtp_end->rtcp_port, buf, len);
- conn_dst->end.packets_tx += 1;
- conn_dst->end.octets_tx += len;
+ conn_dst->end.stats.packets_tx += 1;
+ conn_dst->end.stats.octets_tx += len;
return len;
}
@@ -804,13 +803,13 @@ static int receive_from(struct mgcp_endpoint *endp, int fd,
if (rc < 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x failed to receive packet, errno: %d/%s\n",
+ "endpoint:0x%x failed to receive packet, errno: %d/%s\n",
ENDPOINT_NUMBER(endp), errno, strerror(errno));
return -1;
}
if (tossed) {
- LOGP(DRTP, LOGL_ERROR, "endpoint:%x packet tossed\n",
+ LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
ENDPOINT_NUMBER(endp));
}
@@ -830,11 +829,11 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn,
if (memcmp(&addr->sin_addr, &conn->end.addr, sizeof(addr->sin_addr))
!= 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x data from wrong address: %s, ",
+ "endpoint:0x%x data from wrong address: %s, ",
ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr));
LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
inet_ntoa(conn->end.addr));
- LOGP(DRTP, LOGL_ERROR, "endpoint:%x packet tossed\n",
+ LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -846,12 +845,12 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn,
if (conn->end.rtp_port != addr->sin_port &&
conn->end.rtcp_port != addr->sin_port) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x data from wrong source port: %d, ",
+ "endpoint:0x%x data from wrong source port: %d, ",
ENDPOINT_NUMBER(endp), ntohs(addr->sin_port));
LOGPC(DRTP, LOGL_ERROR,
"expected: %d for RTP or %d for RTCP\n",
ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
- LOGP(DRTP, LOGL_ERROR, "endpoint:%x packet tossed\n",
+ LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -868,14 +867,14 @@ static int check_rtp_destin(struct mgcp_conn_rtp *conn)
if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x destination IP-address is invalid\n",
+ "endpoint:0x%x destination IP-address is invalid\n",
ENDPOINT_NUMBER(endp));
return -1;
}
if (conn->end.rtp_port == 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x destination rtp port is invalid\n",
+ "endpoint:0x%x destination rtp port is invalid\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -897,7 +896,7 @@ static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
endp = conn->conn->endp;
tcfg = endp->tcfg;
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x receiving RTP/RTCP packet...\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x receiving RTP/RTCP packet...\n",
ENDPOINT_NUMBER(endp));
rc = receive_from(endp, fd->fd, addr, buf, buf_size);
@@ -905,11 +904,11 @@ static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
return -1;
*proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x ", ENDPOINT_NUMBER(endp));
- LOGPC(DRTP, LOGL_DEBUG, "receiveing from %s %s %d\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x ", ENDPOINT_NUMBER(endp));
+ LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
conn->conn->name, inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x conn:%s\n", ENDPOINT_NUMBER(endp),
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n", ENDPOINT_NUMBER(endp),
mgcp_conn_dump(conn->conn));
/* Check if the origin of the RTP packet seems plausible */
@@ -921,16 +920,16 @@ static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
/* Filter out dummy message */
if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
LOGP(DRTP, LOGL_NOTICE,
- "endpoint:%x dummy message received\n",
+ "endpoint:0x%x dummy message received\n",
ENDPOINT_NUMBER(endp));
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x packet tossed\n", ENDPOINT_NUMBER(endp));
+ "endpoint:0x%x packet tossed\n", ENDPOINT_NUMBER(endp));
return 0;
}
/* Increment RX statistics */
- conn->end.packets_rx += 1;
- conn->end.octets_rx += rc;
+ conn->end.stats.packets_rx += 1;
+ conn->end.stats.octets_rx += rc;
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(fd->fd, &conn->tap_in, buf, rc);
@@ -948,7 +947,7 @@ static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
struct mgcp_endpoint *endp;
endp = conn_src->conn->endp;
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x destin conn:%s\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x destin conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_dst->conn));
/* Before we try to deliver the packet, we check if the destination
@@ -962,7 +961,7 @@ static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
switch (conn_dst->type) {
case MGCP_RTP_DEFAULT:
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x endpoint type is MGCP_RTP_DEFAULT, "
+ "endpoint:0x%x endpoint type is MGCP_RTP_DEFAULT, "
"using mgcp_send() to forward data directly\n",
ENDPOINT_NUMBER(endp));
return mgcp_send(endp, proto == MGCP_PROTO_RTP,
@@ -970,7 +969,7 @@ static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
case MGCP_OSMUX_BSC_NAT:
case MGCP_OSMUX_BSC:
LOGP(DRTP, LOGL_DEBUG,
- "endpoint:%x endpoint type is MGCP_OSMUX_BSC_NAT, "
+ "endpoint:0x%x endpoint type is MGCP_OSMUX_BSC_NAT, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n",
ENDPOINT_NUMBER(endp));
return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
@@ -980,7 +979,7 @@ static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
* be discarded, this should not happen, normally the MGCP type
* should be properly set */
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x bad MGCP type -- data discarded!\n",
+ "endpoint:0x%x bad MGCP type -- data discarded!\n",
ENDPOINT_NUMBER(endp));
return -1;
@@ -1025,7 +1024,7 @@ int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
/* There is no destination conn, stop here */
if (!conn_dst) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x unable to find destination conn\n",
+ "endpoint:0x%x unable to find destination conn\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -1033,7 +1032,7 @@ int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
/* The destination conn is not an RTP connection */
if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x unable to find suitable destination conn\n",
+ "endpoint:0x%x unable to find suitable destination conn\n",
ENDPOINT_NUMBER(endp));
return -1;
}
@@ -1044,6 +1043,25 @@ int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
}
+/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
+ * \param[in] endp Endpoint on which the connection resides.
+ * \param[in] conn Connection that is about to be removed (ignored).
+ * \returns 0 on success, -1 on ERROR. */
+void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
+{
+ struct mgcp_conn *conn_cleanup;
+
+ /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
+ * pointer to the destination connection, so that we do not have
+ * to go through the list every time an RTP packet arrives. To prevent
+ * a use-after-free situation we invalidate this information for all
+ * connections present when one connection is removed from the
+ * endpoint. */
+ llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
+ conn_cleanup->priv = NULL;
+ }
+}
+
/* Handle incoming RTP data from NET */
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
{
@@ -1067,7 +1085,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
endp = conn_src->conn->endp;
OSMO_ASSERT(endp);
- LOGP(DRTP, LOGL_DEBUG, "endpoint:%x source conn:%s\n",
+ LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x source conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_src->conn));
/* Receive packet */
@@ -1077,7 +1095,16 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
/* Check if the connection is in loopback mode, if yes, just send the
* incoming data back to the origin */
+
if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
+ /* When we are in loopback mode, we loop back all incoming
+ * packets back to their origin. We will use the originating
+ * address data from the UDP packet header to patch the
+ * outgoing address in connection on the fly */
+ if (conn_src->end.rtp_port == 0) {
+ conn_src->end.addr = addr.sin_addr;
+ conn_src->end.rtp_port = addr.sin_port;
+ }
return mgcp_send_rtp(proto, &addr, buf,
len, conn_src, conn_src);
}
@@ -1109,41 +1136,17 @@ int mgcp_set_ip_tos(int fd, int tos)
* \returns 0 on success, -1 on ERROR */
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
{
- struct sockaddr_in addr;
- int on = 1;
-
- fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd->fd < 0) {
- LOGP(DRTP, LOGL_ERROR, "failed to create UDP port (%s:%i).\n",
- source_addr, port);
- return -1;
- } else {
- LOGP(DRTP, LOGL_DEBUG,
- "created UDP port (%s:%i).\n", source_addr, port);
- }
-
- if (setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
- LOGP(DRTP, LOGL_ERROR,
- "failed to set socket options (%s:%i).\n", source_addr,
- port);
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- inet_aton(source_addr, &addr.sin_addr);
+ int rc;
- if (bind(fd->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- close(fd->fd);
- fd->fd = -1;
+ rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
+ NULL, 0, OSMO_SOCK_F_BIND);
+ if (rc < 0) {
LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
source_addr, port);
return -1;
- } else {
- LOGP(DRTP, LOGL_DEBUG,
- "bound UDP port (%s:%i).\n", source_addr, port);
}
+ fd->fd = rc;
+ LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
return 0;
}
@@ -1158,7 +1161,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
if (mgcp_create_bind(source_addr, &rtp_end->rtp,
rtp_end->local_port) != 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x failed to create RTP port: %s:%d\n", endpno,
+ "endpoint:0x%x failed to create RTP port: %s:%d\n", endpno,
source_addr, rtp_end->local_port);
goto cleanup0;
}
@@ -1166,7 +1169,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
rtp_end->local_port + 1) != 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x failed to create RTCP port: %s:%d\n", endpno,
+ "endpoint:0x%x failed to create RTCP port: %s:%d\n", endpno,
source_addr, rtp_end->local_port + 1);
goto cleanup1;
}
@@ -1178,7 +1181,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
rtp_end->rtp.when = BSC_FD_READ;
if (osmo_fd_register(&rtp_end->rtp) != 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x failed to register RTP port %d\n", endpno,
+ "endpoint:0x%x failed to register RTP port %d\n", endpno,
rtp_end->local_port);
goto cleanup2;
}
@@ -1186,7 +1189,7 @@ static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
rtp_end->rtcp.when = BSC_FD_READ;
if (osmo_fd_register(&rtp_end->rtcp) != 0) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x failed to register RTCP port %d\n", endpno,
+ "endpoint:0x%x failed to register RTCP port %d\n", endpno,
rtp_end->local_port + 1);
goto cleanup3;
}
@@ -1217,12 +1220,12 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_rtp_end *end;
char local_ip_addr[INET_ADDRSTRLEN];
- snprintf(name, sizeof(name), "%s-%u", conn->conn->name, conn->conn->id);
+ snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
end = &conn->end;
if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
LOGP(DRTP, LOGL_ERROR,
- "endpoint:%x %u was already bound on conn:%s\n",
+ "endpoint:0x%x %u was already bound on conn:%s\n",
ENDPOINT_NUMBER(endp), rtp_port,
mgcp_conn_dump(conn->conn));
diff --git a/src/libosmo-mgcp/mgcp_osmux.c b/src/libosmo-mgcp/mgcp_osmux.c
index 60ffe06..1d3cab3 100644
--- a/src/libosmo-mgcp/mgcp_osmux.c
+++ b/src/libosmo-mgcp/mgcp_osmux.c
@@ -24,6 +24,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
+#include <osmocom/mgcp/mgcp_endp.h>
static struct osmo_fd osmux_fd;
@@ -142,7 +143,7 @@ osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
}
/* Lookup existing handle for a specified address, if the handle can not be
- * foud a the function will automatically allocate one */
+ * found, the function will automatically allocate one */
static struct osmux_in_handle *
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
{
@@ -207,12 +208,18 @@ endpoint_lookup(struct mgcp_config *cfg, int cid,
case MGCP_DEST_NET:
/* FIXME: Get rid of CONN_ID_XXX! */
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
- this = &conn_net->end.addr;
+ if (conn_net)
+ this = &conn_net->end.addr;
+ else
+ this = NULL;
break;
case MGCP_DEST_BTS:
/* FIXME: Get rid of CONN_ID_XXX! */
conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
- this = &conn_bts->end.addr;
+ if (conn_bts)
+ this = &conn_bts->end.addr;
+ else
+ this = NULL;
break;
default:
/* Should not ever happen */
@@ -222,7 +229,8 @@ endpoint_lookup(struct mgcp_config *cfg, int cid,
/* FIXME: Get rid of CONN_ID_XXX! */
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
- if (conn_net->osmux.cid == cid && this->s_addr == from_addr->s_addr)
+ if (conn_net && this && conn_net->osmux.cid == cid
+ && this->s_addr == from_addr->s_addr)
return endp;
}
@@ -248,8 +256,8 @@ static void scheduled_tx_net_cb(struct msgb *msg, void *data)
.sin_port = conn_net->end.rtp_port,
};
- conn_bts->end.octets_tx += msg->len;
- conn_bts->end.packets_tx++;
+ conn_bts->end.stats.octets_tx += msg->len;
+ conn_bts->end.stats.packets_tx++;
/* Send RTP data to NET */
/* FIXME: Get rid of conn_bts and conn_net! */
@@ -275,8 +283,8 @@ static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
.sin_port = conn_bts->end.rtp_port,
};
- conn_net->end.octets_tx += msg->len;
- conn_net->end.packets_tx++;
+ conn_net->end.stats.octets_tx += msg->len;
+ conn_net->end.stats.packets_tx++;
/* Send RTP data to BTS */
/* FIXME: Get rid of conn_bts and conn_net! */
@@ -566,7 +574,7 @@ void osmux_disable_conn(struct mgcp_conn_rtp *conn)
if (conn->osmux.state != OSMUX_STATE_ENABLED)
return;
- LOGP(DLMGCP, LOGL_INFO, "Releasing connection %u using Osmux CID %u\n",
+ LOGP(DLMGCP, LOGL_INFO, "Releasing connection %s using Osmux CID %u\n",
conn->conn->id, conn->osmux.cid);
osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
conn->osmux.state = OSMUX_STATE_DISABLED;
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 8c6bd6e..ea86672 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -38,7 +38,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/mgcp_msg.h>
-#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_sdp.h>
struct mgcp_request {
@@ -192,17 +192,41 @@ static struct msgb *create_err_response(struct mgcp_endpoint *endp,
return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
}
+/* Add MGCP parameters to a message buffer */
+static int add_params(struct msgb *msg, const struct mgcp_endpoint *endp,
+ const struct mgcp_conn_rtp *conn)
+{
+ int rc;
+
+ /* NOTE: Only in the virtual trunk we allow dynamic endpoint names */
+ if (endp->wildcarded_req
+ && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
+ rc = msgb_printf(msg, "Z: %s%x@%s\r\n",
+ MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
+ ENDPOINT_NUMBER(endp), endp->cfg->domain);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ rc = msgb_printf(msg, "I: %s\r\n", conn->conn->id);
+ if (rc < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
/* Format MGCP response string (with SDP attached) */
static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn,
const char *msg,
- const char *trans_id)
+ const char *trans_id,
+ bool add_conn_params)
{
const char *addr = endp->cfg->local_ip;
struct msgb *sdp;
int rc;
struct msgb *result;
- char osmux_extension[strlen("\nX-Osmux: 255") + 1];
+ char osmux_extension[strlen("X-Osmux: 255") + 1];
char local_ip_addr[INET_ADDRSTRLEN];
sdp = msgb_alloc_headroom(4096, 128, "sdp record");
@@ -215,15 +239,28 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
}
if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
- sprintf(osmux_extension, "\nX-Osmux: %u", conn->osmux.cid);
+ sprintf(osmux_extension, "X-Osmux: %u", conn->osmux.cid);
conn->osmux.state = OSMUX_STATE_ACTIVATING;
} else {
osmux_extension[0] = '\0';
}
- rc = msgb_printf(sdp, "I: %u%s\n\n", conn->conn->id, osmux_extension);
- if (rc < 0)
- goto error;
+ /* Attach optional connection parameters */
+ if (add_conn_params) {
+ rc = add_params(sdp, endp, conn);
+ if (rc < 0)
+ goto error;
+ }
+
+ /* Attach optional OSMUX parameters */
+ if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
+ rc = msgb_printf(sdp, "%s\r\n", osmux_extension);
+ if (rc < 0)
+ goto error;
+ }
+
+ /* Attach line break to separate the parameters from the SDP block */
+ rc = msgb_printf(sdp, "\r\n");
rc = mgcp_write_response_sdp(endp, conn, sdp, addr);
if (rc < 0)
@@ -252,7 +289,7 @@ static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
{
struct mgcp_parse_data pdata;
- int i, code, handled = 0;
+ int rc, i, code, handled = 0;
struct msgb *resp = NULL;
char *data;
@@ -280,13 +317,19 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
memset(&pdata, 0, sizeof(pdata));
pdata.cfg = cfg;
data = mgcp_strline((char *)msg->l3h, &pdata.save);
- pdata.found = mgcp_parse_header(&pdata, data);
+ rc = mgcp_parse_header(&pdata, data);
if (pdata.endp && pdata.trans
&& pdata.endp->last_trans
&& strcmp(pdata.endp->last_trans, pdata.trans) == 0) {
return do_retransmission(pdata.endp);
}
+ /* check for general parser failure */
+ if (rc < 0) {
+ LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to find the endpoint\n", msg->l2h);
+ return create_err_response(NULL, -rc, (const char *) msg->l2h, pdata.trans);
+ }
+
for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) {
if (strncmp
(mgcp_requests[i].name, (const char *)&msg->l2h[0],
@@ -308,19 +351,13 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
{
LOGP(DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
-
- if (p->found != 0) {
- LOGP(DLMGCP, LOGL_ERROR,
- "AUEP: failed to find the endpoint.\n");
- return create_err_response(NULL, 500, "AUEP", p->trans);
- } else
- return create_ok_response(p->endp, 200, "AUEP", p->trans);
+ return create_ok_response(p->endp, 200, "AUEP", p->trans);
}
-/* Try to find a free port by attemting to bind on it. Also handle the
+/* 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 work on the first attemt,
- * neverless, try at least the next 200 ports before giving up */
+ * to the next free port, binding should work on the first attempt,
+ * nevertheless, try at least the next 200 ports before giving up */
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int i;
@@ -356,10 +393,10 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
}
/* Set the LCO from a string (see RFC 3435).
- * The string is stored in the 'string' field. A NULL string is handled excatlyy
+ * The string is stored in the 'string' field. A NULL string is handled exactly
* like an empty string, the 'string' field is never NULL after this function
* has been called. */
-static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
+static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
const char *options)
{
char *p_opt, *a_opt;
@@ -383,6 +420,15 @@ static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
LOGP(DLMGCP, LOGL_DEBUG,
"local CX options: lco->pkt_period_max: %i, lco->codec: %s\n",
lco->pkt_period_max, lco->codec);
+
+ /* Check if the packetization fits the 20ms raster */
+ if (lco->pkt_period_min % 20 && lco->pkt_period_max % 20) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "local CX options: packetization interval is not a multiple of 20ms!\n");
+ return 535;
+ }
+
+ return 0;
}
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
@@ -443,19 +489,16 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
const char *local_options = NULL;
const char *callid = NULL;
- const char *ci = NULL;
const char *mode = NULL;
char *line;
int have_sdp = 0, osmux_cid = -1;
struct mgcp_conn_rtp *conn = NULL;
- uint32_t conn_id;
+ struct mgcp_conn *_conn = NULL;
char conn_name[512];
+ int rc;
LOGP(DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
- if (p->found != 0)
- return create_err_response(NULL, 510, "CRCX", p->trans);
-
/* parse CallID C: and LocalParameters L: */
for_each_line(line, p->save) {
if (!mgcp_check_param(endp, line))
@@ -469,7 +512,10 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
callid = (const char *)line + 3;
break;
case 'I':
- ci = (const char *)line + 3;
+ /* It is illegal to send a connection identifier
+ * together with a CRCX, the MGW will assign the
+ * connection identifier by itself on CRCX */
+ return create_err_response(NULL, 523, "CRCX", p->trans);
break;
case 'M':
mode = (const char *)line + 3;
@@ -489,6 +535,7 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
LOGP(DLMGCP, LOGL_NOTICE,
"CRCX: endpoint:%x unhandled option: '%c'/%d\n",
ENDPOINT_NUMBER(endp), *line, *line);
+ return create_err_response(NULL, 539, "CRCX", p->trans);
break;
}
}
@@ -501,21 +548,14 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x insufficient parameters, missing callid\n",
ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
+ return create_err_response(endp, 516, "CRCX", p->trans);
}
if (!mode) {
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x insufficient parameters, missing mode\n",
ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
-
- if (!ci) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x insufficient parameters, missing connection id\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
+ return create_err_response(endp, 517, "CRCX", p->trans);
}
/* Check if we are able to accept the creation of another connection */
@@ -531,7 +571,7 @@ mgcp_header_done:
} else {
/* There is no more room for a connection, leave
* everything as it is and return with an error */
- return create_err_response(endp, 400, "CRCX", p->trans);
+ return create_err_response(endp, 540, "CRCX", p->trans);
}
}
@@ -539,12 +579,12 @@ mgcp_header_done:
* callids match up so that we are sure that this is our call */
if (endp->callid && mgcp_verify_call_id(endp, callid)) {
LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x allready seized by other call (%s)\n",
+ "CRCX: endpoint:0x%x allready seized by other call (%s)\n",
ENDPOINT_NUMBER(endp), endp->callid);
if (tcfg->force_realloc)
/* This is not our call, toss everything by releasing
* the entire endpoint. (rude!) */
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
else {
/* This is not our call, leave everything as it is and
* return with an error. */
@@ -553,47 +593,32 @@ mgcp_header_done:
}
/* Set the callid, creation of another connection will only be possible
- * when the callid matches up. (Connections are distinuished by their
+ * when the callid matches up. (Connections are distinguished by their
* connection ids) */
endp->callid = talloc_strdup(tcfg->endpoints, callid);
/* Extract audio codec information */
- set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
- local_options);
-
- if (mgcp_parse_ci(&conn_id, ci)) {
+ rc = set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
+ local_options);
+ if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x insufficient parameters, missing ci (connectionIdentifier)\n",
+ "CRCX: endpoint:%x inavlid local connection options!\n",
ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
-
- /* Only accept another connection when the connection ID is different. */
- if (mgcp_conn_get_rtp(endp, conn_id)) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x there is already a connection with id %u present!\n",
- conn_id, ENDPOINT_NUMBER(endp));
- if (tcfg->force_realloc) {
- /* Ignore the existing connection by just freeing it */
- mgcp_conn_free(endp, conn_id);
- } else {
- /* There is already a connection with that ID present,
- * leave everything as it is and return with an error. */
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
+ error_code = rc;
+ goto error2;
}
- snprintf(conn_name, sizeof(conn_name), "%s-%u", callid, conn_id);
- mgcp_conn_alloc(NULL, endp, conn_id, MGCP_CONN_TYPE_RTP,
- conn_name);
- conn = mgcp_conn_get_rtp(endp, conn_id);
- if (!conn) {
+ snprintf(conn_name, sizeof(conn_name), "%s", callid);
+ _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
+ if (!_conn) {
LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x unable to allocate RTP connection\n",
+ "CRCX: endpoint:0x%x unable to allocate RTP connection\n",
ENDPOINT_NUMBER(endp));
goto error2;
}
+ conn = mgcp_conn_get_rtp(endp, _conn->id);
+ OSMO_ASSERT(conn);
if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
error_code = 517;
@@ -608,7 +633,7 @@ mgcp_header_done:
conn->osmux.state = OSMUX_STATE_NEGOTIATING;
} else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x osmux only and no osmux offered\n",
+ "CRCX: endpoint:0x%x osmux only and no osmux offered\n",
ENDPOINT_NUMBER(endp));
goto error2;
}
@@ -629,13 +654,24 @@ mgcp_header_done:
mgcp_rtp_end_config(endp, 0, &conn->end);
+ /* check connection mode setting */
+ if (conn->conn->mode != MGCP_CONN_LOOPBACK
+ && conn->conn->mode != MGCP_CONN_RECV_ONLY
+ && conn->end.rtp_port == 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "CRCX: endpoint:%x selected connection mode type requires an opposite end!\n",
+ ENDPOINT_NUMBER(endp));
+ error_code = 527;
+ goto error2;
+ }
+
if (allocate_port(endp, conn) != 0) {
goto error2;
}
if (setup_rtp_processing(endp, conn) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x could not start RTP processing!\n",
+ "CRCX: endpoint:0x%x could not start RTP processing!\n",
ENDPOINT_NUMBER(endp));
goto error2;
}
@@ -648,9 +684,9 @@ mgcp_header_done:
switch (rc) {
case MGCP_POLICY_REJECT:
LOGP(DLMGCP, LOGL_NOTICE,
- "CRCX: endpoint:%x CRCX rejected by policy\n",
+ "CRCX: endpoint:0x%x CRCX rejected by policy\n",
ENDPOINT_NUMBER(endp));
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
return create_err_response(endp, 400, "CRCX", p->trans);
break;
case MGCP_POLICY_DEFER:
@@ -664,7 +700,7 @@ mgcp_header_done:
}
LOGP(DLMGCP, LOGL_DEBUG,
- "CRCX: endpoint:%x Creating connection: CI: %u port: %u\n",
+ "CRCX: endpoint:0x%x Creating connection: CI: %s port: %u\n",
ENDPOINT_NUMBER(endp), conn->conn->id, conn->end.local_port);
if (p->cfg->change_cb)
p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
@@ -676,13 +712,13 @@ mgcp_header_done:
send_dummy(endp, conn);
LOGP(DLMGCP, LOGL_NOTICE,
- "CRCX: endpoint:%x connection successfully created\n",
+ "CRCX: endpoint:0x%x connection successfully created\n",
ENDPOINT_NUMBER(endp));
- return create_response_with_sdp(endp, conn, "CRCX", p->trans);
+ return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
error2:
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
LOGP(DLMGCP, LOGL_NOTICE,
- "CRCX: endpoint:%x unable to create connection resource error\n",
+ "CRCX: endpoint:0x%x unable to create connection resource error\n",
ENDPOINT_NUMBER(endp));
return create_err_response(endp, error_code, "CRCX", p->trans);
}
@@ -695,20 +731,25 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
int silent = 0;
int have_sdp = 0;
char *line;
- const char *ci = NULL;
const char *local_options = NULL;
const char *mode = NULL;
struct mgcp_conn_rtp *conn = NULL;
- uint32_t conn_id;
+ const char *conn_id = NULL;
+ int rc;
LOGP(DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
- if (p->found != 0)
- return create_err_response(NULL, 510, "MDCX", p->trans);
+ /* Prohibit wildcarded requests */
+ if (endp->wildcarded_req) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "MDCX: endpoint:0x%x wildcarded endpoint names not supported.\n",
+ ENDPOINT_NUMBER(endp));
+ return create_err_response(endp, 507, "MDCX", p->trans);
+ }
if (llist_count(&endp->conns) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "MDCX: endpoint:%x endpoint is not holding a connection.\n",
+ "MDCX: endpoint:0x%x endpoint is not holding a connection.\n",
ENDPOINT_NUMBER(endp));
return create_err_response(endp, 400, "MDCX", p->trans);
}
@@ -719,13 +760,17 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
switch (line[0]) {
case 'C':
- if (mgcp_verify_call_id(endp, line + 3) != 0)
+ if (mgcp_verify_call_id(endp, line + 3) != 0) {
+ error_code = 516;
goto error3;
+ }
break;
case 'I':
- ci = (const char *)line + 3;
- if (mgcp_verify_ci(endp, ci) != 0)
+ conn_id = (const char *)line + 3;
+ if (mgcp_verify_ci(endp, conn_id) != 0) {
+ error_code = 515;
goto error3;
+ }
break;
case 'L':
local_options = (const char *)line + 3;
@@ -742,18 +787,19 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
break;
default:
LOGP(DLMGCP, LOGL_NOTICE,
- "MDCX: endpoint:%x Unhandled MGCP option: '%c'/%d\n",
+ "MDCX: endpoint:0x%x Unhandled MGCP option: '%c'/%d\n",
ENDPOINT_NUMBER(endp), line[0], line[0]);
+ return create_err_response(NULL, 539, "MDCX", p->trans);
break;
}
}
mgcp_header_done:
- if (mgcp_parse_ci(&conn_id, ci)) {
+ if (!conn_id) {
LOGP(DLMGCP, LOGL_ERROR,
- "MDCX: endpoint:%x insufficient parameters, missing ci (connectionIdentifier)\n",
+ "MDCX: endpoint:0x%x insufficient parameters, missing ci (connectionIdentifier)\n",
ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "MDCX", p->trans);
+ return create_err_response(endp, 515, "MDCX", p->trans);
}
conn = mgcp_conn_get_rtp(endp, conn_id);
@@ -771,13 +817,31 @@ mgcp_header_done:
if (have_sdp)
mgcp_parse_sdp_data(endp, conn, p);
- set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
- local_options);
+ rc = set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
+ local_options);
+ if (rc != 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "MDCX: endpoint:%x inavlid local connection options!\n",
+ ENDPOINT_NUMBER(endp));
+ error_code = rc;
+ goto error3;
+ }
if (!have_sdp && endp->local_options.codec)
mgcp_set_audio_info(p->cfg, &conn->end.codec,
PTYPE_UNDEFINED, endp->local_options.codec);
+ /* check connection mode setting */
+ if (conn->conn->mode != MGCP_CONN_LOOPBACK
+ && conn->conn->mode != MGCP_CONN_RECV_ONLY
+ && conn->end.rtp_port == 0) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "MDCX: endpoint:%x selected connection mode type requires an opposite end!\n",
+ ENDPOINT_NUMBER(endp));
+ error_code = 527;
+ goto error3;
+ }
+
if (setup_rtp_processing(endp, conn) != 0)
goto error3;
@@ -790,7 +854,7 @@ mgcp_header_done:
switch (rc) {
case MGCP_POLICY_REJECT:
LOGP(DLMGCP, LOGL_NOTICE,
- "MDCX: endpoint:%x rejected by policy\n",
+ "MDCX: endpoint:0x%x rejected by policy\n",
ENDPOINT_NUMBER(endp));
if (silent)
goto out_silent;
@@ -799,7 +863,7 @@ mgcp_header_done:
case MGCP_POLICY_DEFER:
/* stop processing */
LOGP(DLMGCP, LOGL_DEBUG,
- "MDCX: endpoint:%x defered by policy\n",
+ "MDCX: endpoint:0x%x defered by policy\n",
ENDPOINT_NUMBER(endp));
return NULL;
break;
@@ -813,7 +877,7 @@ mgcp_header_done:
/* modify */
LOGP(DLMGCP, LOGL_DEBUG,
- "MDCX: endpoint:%x modified conn:%s\n",
+ "MDCX: endpoint:0x%x modified conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
if (p->cfg->change_cb)
p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
@@ -829,14 +893,14 @@ mgcp_header_done:
goto out_silent;
LOGP(DLMGCP, LOGL_NOTICE,
- "MDCX: endpoint:%x connection successfully modified\n",
+ "MDCX: endpoint:0x%x connection successfully modified\n",
ENDPOINT_NUMBER(endp));
- return create_response_with_sdp(endp, conn, "MDCX", p->trans);
+ return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
error3:
return create_err_response(endp, error_code, "MDCX", p->trans);
out_silent:
- LOGP(DLMGCP, LOGL_DEBUG, "MDCX: endpoint:%x silent exit\n",
+ LOGP(DLMGCP, LOGL_DEBUG, "MDCX: endpoint:0x%x silent exit\n",
ENDPOINT_NUMBER(endp));
return NULL;
}
@@ -849,22 +913,26 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
int silent = 0;
char *line;
char stats[1048];
- const char *ci = NULL;
+ const char *conn_id = NULL;
struct mgcp_conn_rtp *conn = NULL;
- uint32_t conn_id;
LOGP(DLMGCP, LOGL_NOTICE,
- "DLCX: endpoint:%x deleting connection ...\n",
+ "DLCX: endpoint:0x%x deleting connection ...\n",
ENDPOINT_NUMBER(endp));
- if (p->found != 0)
- return create_err_response(NULL, error_code, "DLCX", p->trans);
+ /* Prohibit wildcarded requests */
+ if (endp->wildcarded_req) {
+ LOGP(DLMGCP, LOGL_ERROR,
+ "DLCX: endpoint:0x%x wildcarded endpoint names not supported.\n",
+ ENDPOINT_NUMBER(endp));
+ return create_err_response(endp, 507, "DLCX", p->trans);
+ }
if (llist_count(&endp->conns) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "DLCX: endpoint:%x endpoint is not holding a connection.\n",
+ "DLCX: endpoint:0x%x endpoint is not holding a connection.\n",
ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "DLCX", p->trans);
+ return create_err_response(endp, 515, "DLCX", p->trans);
}
for_each_line(line, p->save) {
@@ -873,21 +941,26 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
switch (line[0]) {
case 'C':
- if (mgcp_verify_call_id(endp, line + 3) != 0)
+ if (mgcp_verify_call_id(endp, line + 3) != 0) {
+ error_code = 516;
goto error3;
+ }
break;
case 'I':
- ci = (const char *)line + 3;
- if (mgcp_verify_ci(endp, ci) != 0)
+ conn_id = (const char *)line + 3;
+ if (mgcp_verify_ci(endp, conn_id) != 0) {
+ error_code = 515;
goto error3;
+ }
break;
case 'Z':
silent = strcmp("noanswer", line + 3) == 0;
break;
default:
LOGP(DLMGCP, LOGL_NOTICE,
- "DLCX: endpoint:%x Unhandled MGCP option: '%c'/%d\n",
+ "DLCX: endpoint:0x%x Unhandled MGCP option: '%c'/%d\n",
ENDPOINT_NUMBER(endp), line[0], line[0]);
+ return create_err_response(NULL, 539, "DLCX", p->trans);
break;
}
}
@@ -900,7 +973,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
switch (rc) {
case MGCP_POLICY_REJECT:
LOGP(DLMGCP, LOGL_NOTICE,
- "DLCX: endpoint:%x rejected by policy\n",
+ "DLCX: endpoint:0x%x rejected by policy\n",
ENDPOINT_NUMBER(endp));
if (silent)
goto out_silent;
@@ -919,12 +992,12 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
/* When no connection id is supplied, we will interpret this as a
* wildcarded DLCX and drop all connections at once. (See also
* RFC3435 Section F.7) */
- if (!ci) {
+ if (!conn_id) {
LOGP(DLMGCP, LOGL_NOTICE,
- "DLCX: endpoint:%x missing ci (connectionIdentifier), will remove all connections at once\n",
+ "DLCX: endpoint:0x%x missing ci (connectionIdentifier), will remove all connections at once\n",
ENDPOINT_NUMBER(endp));
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
/* Note: In this case we do not return any statistics,
* as we assume that the client is not interested in
@@ -932,14 +1005,6 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
return create_ok_response(endp, 200, "DLCX", p->trans);
}
- /* Parse the connection id */
- if (mgcp_parse_ci(&conn_id, ci)) {
- LOGP(DLMGCP, LOGL_ERROR,
- "DLCX: endpoint:%x insufficient parameters, invalid ci (connectionIdentifier)\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "DLCX", p->trans);
- }
-
/* Find the connection */
conn = mgcp_conn_get_rtp(endp, conn_id);
if (!conn)
@@ -949,19 +1014,19 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
mgcp_format_stats(stats, sizeof(stats), conn->conn);
/* delete connection */
- LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:%x deleting conn:%s\n",
+ LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:0x%x deleting conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
mgcp_conn_free(endp, conn_id);
LOGP(DLMGCP, LOGL_NOTICE,
- "DLCX: endpoint:%x connection successfully deleted\n",
+ "DLCX: endpoint:0x%x connection successfully deleted\n",
ENDPOINT_NUMBER(endp));
/* When all connections are closed, the endpoint will be released
* in order to be ready to be used by another call. */
if (llist_count(&endp->conns) <= 0) {
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
LOGP(DLMGCP, LOGL_DEBUG,
- "DLCX: endpoint:%x endpoint released\n",
+ "DLCX: endpoint:0x%x endpoint released\n",
ENDPOINT_NUMBER(endp));
}
@@ -977,7 +1042,7 @@ error3:
return create_err_response(endp, error_code, "DLCX", p->trans);
out_silent:
- LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:%x silent exit\n",
+ LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:0x%x silent exit\n",
ENDPOINT_NUMBER(endp));
return NULL;
}
@@ -995,12 +1060,6 @@ static struct msgb *handle_rsip(struct mgcp_parse_data *p)
LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
- if (p->found != 0) {
- LOGP(DLMGCP, LOGL_ERROR,
- "RSIP: failed to find the endpoint.\n");
- return NULL;
- }
-
if (p->cfg->reset_cb)
p->cfg->reset_cb(p->endp->tcfg);
return NULL;
@@ -1026,9 +1085,6 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
- if (p->found != 0)
- return create_err_response(NULL, 400, "RQNT", p->trans);
-
for_each_line(line, p->save) {
switch (line[0]) {
case 'S':
@@ -1050,7 +1106,7 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
}
/* Connection keepalive timer, will take care that dummy packets are send
- * regulary, so that NAT connections stay open */
+ * regularly, so that NAT connections stay open */
static void mgcp_keepalive_timer_cb(void *_tcfg)
{
struct mgcp_trunk_config *tcfg = _tcfg;
@@ -1119,6 +1175,8 @@ struct mgcp_config *mgcp_config_alloc(void)
return NULL;
}
+ osmo_strlcpy(cfg->domain, "mgw", sizeof(cfg->domain));
+
cfg->net_ports.range_start = RTP_PORT_DEFAULT_RANGE_START;
cfg->net_ports.range_end = RTP_PORT_DEFAULT_RANGE_END;
cfg->net_ports.last_port = cfg->net_ports.range_start;
@@ -1170,7 +1228,7 @@ struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
trunk->audio_payload = 126;
trunk->audio_send_ptime = 1;
trunk->audio_send_name = 1;
- trunk->number_endpoints = 33;
+ trunk->vty_number_endpoints = 33;
trunk->omit_rtcp = 0;
mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
llist_add_tail(&trunk->entry, &cfg->trunks);
@@ -1202,12 +1260,12 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
sizeof(struct mgcp_endpoint),
- tcfg->number_endpoints,
+ tcfg->vty_number_endpoints,
"endpoints");
if (!tcfg->endpoints)
return -1;
- for (i = 0; i < tcfg->number_endpoints; ++i) {
+ for (i = 0; i < tcfg->vty_number_endpoints; ++i) {
INIT_LLIST_HEAD(&tcfg->endpoints[i].conns);
tcfg->endpoints[i].cfg = tcfg->cfg;
tcfg->endpoints[i].tcfg = tcfg;
@@ -1217,31 +1275,10 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
tcfg->endpoints[i].type = &ep_typeset.rtp;
}
+ tcfg->number_endpoints = tcfg->vty_number_endpoints;
return 0;
}
-/*! relase endpoint, all open connections are closed.
- * \param[in] endp endpoint to release */
-void mgcp_release_endp(struct mgcp_endpoint *endp)
-{
- LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint:%x\n",
- ENDPOINT_NUMBER(endp));
-
- /* Normally this function should only be called wehen
- * all connections have been removed already. In case
- * that there are still connections open (e.g. when
- * RSIP is executed), free them all at once. */
- mgcp_conn_free_all(endp);
-
- /* Reset endpoint parameters and states */
- talloc_free(endp->callid);
- endp->callid = NULL;
- talloc_free(endp->local_options.string);
- endp->local_options.string = NULL;
- talloc_free(endp->local_options.codec);
- endp->local_options.codec = NULL;
-}
-
static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
{
return write(cfg->gw_fd.bfd.fd, buf, len);
@@ -1254,13 +1291,16 @@ static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
* \returns 0 on success, -1 on error */
int mgcp_send_reset_all(struct mgcp_config *cfg)
{
+ char buf[MGCP_ENDPOINT_MAXLEN + 128];
+ int len;
int rc;
- static const char mgcp_reset[] = {
- "RSIP 1 *@mgw MGCP 1.0\r\n"
- };
+ len = snprintf(buf, sizeof(buf),
+ "RSIP 1 *@%s MGCP 1.0\r\n", cfg->domain);
+ if (len < 0)
+ return -1;
- rc = send_agent(cfg, mgcp_reset, sizeof mgcp_reset - 1);
+ rc = send_agent(cfg, buf, len);
if (rc <= 0)
return -1;
@@ -1274,17 +1314,15 @@ int mgcp_send_reset_all(struct mgcp_config *cfg)
* \returns 0 on success, -1 on error */
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
{
- char buf[128];
+ char buf[MGCP_ENDPOINT_MAXLEN + 128];
int len;
int rc;
len = snprintf(buf, sizeof(buf),
- "RSIP 39 %x@mgw MGCP 1.0\r\n", endpoint);
+ "RSIP 39 %x@%s MGCP 1.0\r\n", endpoint, endp->cfg->domain);
if (len < 0)
return -1;
- buf[sizeof(buf) - 1] = '\0';
-
rc = send_agent(endp->cfg, buf, len);
if (rc <= 0)
return -1;
diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c
index f45d6e7..52b4df4 100644
--- a/src/libosmo-mgcp/mgcp_sdp.c
+++ b/src/libosmo-mgcp/mgcp_sdp.c
@@ -24,6 +24,7 @@
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_msg.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <errno.h>
@@ -365,7 +366,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
rc = msgb_printf(sdp,
"v=0\r\n"
- "o=- %u 23 IN IP4 %s\r\n"
+ "o=- %s 23 IN IP4 %s\r\n"
"s=-\r\n"
"c=IN IP4 %s\r\n"
"t=0 0\r\n", conn->conn->id, addr, addr);
diff --git a/src/libosmo-mgcp/mgcp_stat.c b/src/libosmo-mgcp/mgcp_stat.c
index b84f5f2..581130c 100644
--- a/src/libosmo-mgcp/mgcp_stat.c
+++ b/src/libosmo-mgcp/mgcp_stat.c
@@ -23,6 +23,7 @@
*/
#include <osmocom/mgcp/mgcp_stat.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <limits.h>
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
@@ -30,10 +31,10 @@ void calc_loss(struct mgcp_rtp_state *state,
struct mgcp_rtp_end *end, uint32_t *expected,
int *loss)
{
- *expected = state->stats_cycles + state->stats_max_seq;
- *expected = *expected - state->stats_base_seq + 1;
+ *expected = state->stats.cycles + state->stats.max_seq;
+ *expected = *expected - state->stats.base_seq + 1;
- if (!state->stats_initialized) {
+ if (!state->stats.initialized) {
*expected = 0;
*loss = 0;
return;
@@ -43,8 +44,8 @@ void calc_loss(struct mgcp_rtp_state *state,
* Make sure the sign is correct and use the biggest
* positive/negative number that fits.
*/
- *loss = *expected - end->packets_rx;
- if (*expected < end->packets_rx) {
+ *loss = *expected - end->stats.packets_rx;
+ if (*expected < end->stats.packets_rx) {
if (*loss > 0)
*loss = INT_MIN;
} else {
@@ -56,9 +57,9 @@ void calc_loss(struct mgcp_rtp_state *state,
/* Helper function for mgcp_format_stats_rtp() to calculate jitter */
uint32_t calc_jitter(struct mgcp_rtp_state *state)
{
- if (!state->stats_initialized)
+ if (!state->stats.initialized)
return 0;
- return state->stats_jitter >> 4;
+ return state->stats.jitter >> 4;
}
/* Generate statistics for an RTP connection */
@@ -74,8 +75,8 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
nchars = snprintf(str, str_len,
"\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
- conn->end.packets_tx, conn->end.octets_tx,
- conn->end.packets_rx, conn->end.octets_rx,
+ conn->end.stats.packets_tx, conn->end.stats.octets_tx,
+ conn->end.stats.packets_rx, conn->end.stats.octets_rx,
ploss, jitter);
if (nchars < 0 || nchars >= str_len)
goto truncate;
@@ -83,21 +84,23 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
str += nchars;
str_len -= nchars;
- /* Error Counter */
- nchars = snprintf(str, str_len,
- "\r\nX-Osmo-CP: EC TI=%u, TO=%u",
- conn->state.in_stream.err_ts_counter,
- conn->state.out_stream.err_ts_counter);
- if (nchars < 0 || nchars >= str_len)
- goto truncate;
-
- str += nchars;
- str_len -= nchars;
-
- if (conn->osmux.state == OSMUX_STATE_ENABLED) {
- snprintf(str, str_len,
- "\r\nX-Osmux-ST: CR=%u, BR=%u",
- conn->osmux.stats.chunks, conn->osmux.stats.octets);
+ if (conn->conn->endp->cfg->osmux != OSMUX_USAGE_OFF) {
+ /* Error Counter */
+ nchars = snprintf(str, str_len,
+ "\r\nX-Osmo-CP: EC TI=%u, TO=%u",
+ conn->state.in_stream.err_ts_counter,
+ conn->state.out_stream.err_ts_counter);
+ if (nchars < 0 || nchars >= str_len)
+ goto truncate;
+
+ str += nchars;
+ str_len -= nchars;
+
+ if (conn->osmux.state == OSMUX_STATE_ENABLED) {
+ snprintf(str, str_len,
+ "\r\nX-Osmux-ST: CR=%u, BR=%u",
+ conn->osmux.stats.chunks, conn->osmux.stats.octets);
+ }
}
truncate:
diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c
index 7ff1fdd..14ecd17 100644
--- a/src/libosmo-mgcp/mgcp_vty.c
+++ b/src/libosmo-mgcp/mgcp_vty.c
@@ -27,6 +27,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/vty.h>
#include <osmocom/mgcp/mgcp_conn.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <string.h>
@@ -63,15 +64,16 @@ struct cmd_node trunk_node = {
static int config_write_mgcp(struct vty *vty)
{
vty_out(vty, "mgcp%s", VTY_NEWLINE);
+ vty_out(vty, " domain %s%s", g_cfg->domain, VTY_NEWLINE);
if (g_cfg->local_ip)
vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
- vty_out(vty, " rtp net-range %u %u%s",
+ vty_out(vty, " rtp port-range %u %u%s",
g_cfg->net_ports.range_start, g_cfg->net_ports.range_end,
VTY_NEWLINE);
if (g_cfg->net_ports.bind_addr)
- vty_out(vty, " rtp net-bind-ip %s%s",
+ vty_out(vty, " rtp bind-ip %s%s",
g_cfg->net_ports.bind_addr, VTY_NEWLINE);
if (g_cfg->net_ports.bind_addr_probe)
vty_out(vty, " rtp ip-probing%s", VTY_NEWLINE);
@@ -115,7 +117,7 @@ static int config_write_mgcp(struct vty *vty)
g_cfg->trunk.audio_send_name ? "" : "no ", VTY_NEWLINE);
vty_out(vty, " loop %u%s", ! !g_cfg->trunk.audio_loop, VTY_NEWLINE);
vty_out(vty, " number endpoints %u%s",
- g_cfg->trunk.number_endpoints - 1, VTY_NEWLINE);
+ g_cfg->trunk.vty_number_endpoints - 1, VTY_NEWLINE);
vty_out(vty, " %sallow-transcoding%s",
g_cfg->trunk.no_audio_transcoding ? "no " : "", VTY_NEWLINE);
if (g_cfg->call_agent_addr)
@@ -167,7 +169,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_rtp_state *state,
" Output-Enabled: %d Force-PTIME: %d%s",
state->in_stream.err_ts_counter,
state->out_stream.err_ts_counter, VTY_NEWLINE,
- end->dropped_packets, VTY_NEWLINE,
+ end->stats.dropped_packets, VTY_NEWLINE,
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
codec->frame_duration_num, codec->frame_duration_den,
VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
@@ -292,28 +294,37 @@ static void parse_range(struct mgcp_port_range *range, const char **argv)
#define RANGE_START_STR "Start of the range of ports\n"
#define RANGE_END_STR "End of the range of ports\n"
-DEFUN(cfg_mgcp_rtp_net_range,
- cfg_mgcp_rtp_net_range_cmd,
- "rtp net-range <0-65534> <0-65534>",
+DEFUN(cfg_mgcp_rtp_port_range,
+ cfg_mgcp_rtp_port_range_cmd,
+ "rtp port-range <0-65534> <0-65534>",
RTP_STR "Range of ports to use for the NET side\n"
RANGE_START_STR RANGE_END_STR)
{
parse_range(&g_cfg->net_ports, argv);
return CMD_SUCCESS;
}
+ALIAS_DEPRECATED(cfg_mgcp_rtp_port_range,
+ cfg_mgcp_rtp_net_range_cmd,
+ "rtp net-range <0-65534> <0-65534>",
+ RTP_STR "Range of ports to use for the NET side\n"
+ RANGE_START_STR RANGE_END_STR)
-DEFUN(cfg_mgcp_rtp_net_bind_ip,
- cfg_mgcp_rtp_net_bind_ip_cmd,
- "rtp net-bind-ip A.B.C.D",
+DEFUN(cfg_mgcp_rtp_bind_ip,
+ cfg_mgcp_rtp_bind_ip_cmd,
+ "rtp bind-ip A.B.C.D",
RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
{
osmo_talloc_replace_string(g_cfg, &g_cfg->net_ports.bind_addr, argv[0]);
return CMD_SUCCESS;
}
+ALIAS_DEPRECATED(cfg_mgcp_rtp_bind_ip,
+ cfg_mgcp_rtp_net_bind_ip_cmd,
+ "rtp net-bind-ip A.B.C.D",
+ RTP_STR "Bind endpoints facing the Network\n" "Address to bind to\n")
-DEFUN(cfg_mgcp_rtp_no_net_bind_ip,
- cfg_mgcp_rtp_no_net_bind_ip_cmd,
- "no rtp net-bind-ip",
+DEFUN(cfg_mgcp_rtp_no_bind_ip,
+ cfg_mgcp_rtp_no_bind_ip_cmd,
+ "no rtp bind-ip",
NO_STR RTP_STR "Bind endpoints facing the Network\n"
"Address to bind to\n")
{
@@ -321,6 +332,11 @@ DEFUN(cfg_mgcp_rtp_no_net_bind_ip,
g_cfg->net_ports.bind_addr = NULL;
return CMD_SUCCESS;
}
+ALIAS_DEPRECATED(cfg_mgcp_rtp_no_bind_ip,
+ cfg_mgcp_rtp_no_net_bind_ip_cmd,
+ "no rtp net-bind-ip",
+ NO_STR RTP_STR "Bind endpoints facing the Network\n"
+ "Address to bind to\n")
DEFUN(cfg_mgcp_rtp_net_bind_ip_probing,
cfg_mgcp_rtp_net_bind_ip_probing_cmd,
@@ -510,7 +526,7 @@ DEFUN(cfg_mgcp_number_endp,
"Number options\n" "Endpoints available\n" "Number endpoints\n")
{
/* + 1 as we start counting at one */
- g_cfg->trunk.number_endpoints = atoi(argv[0]) + 1;
+ g_cfg->trunk.vty_number_endpoints = atoi(argv[0]) + 1;
return CMD_SUCCESS;
}
@@ -956,7 +972,7 @@ DEFUN(tap_rtp,
struct mgcp_trunk_config *trunk;
struct mgcp_endpoint *endp;
struct mgcp_conn_rtp *conn;
- uint32_t conn_id;
+ const char *conn_id = NULL;
trunk = find_trunk(g_cfg, atoi(argv[0]));
if (!trunk) {
@@ -980,11 +996,11 @@ DEFUN(tap_rtp,
endp = &trunk->endpoints[endp_no];
- conn_id = strtoul(argv[2], NULL, 10);
+ conn_id = argv[2];
conn = mgcp_conn_get_rtp(endp, conn_id);
if (!conn) {
- vty_out(vty, "Conn ID %s/%d is invalid.%s",
- argv[2], conn_id, VTY_NEWLINE);
+ vty_out(vty, "Conn ID %s is invalid.%s",
+ conn_id, VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1032,7 +1048,7 @@ DEFUN(free_endp, free_endp_cmd,
}
endp = &trunk->endpoints[endp_no];
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
return CMD_SUCCESS;
}
@@ -1102,7 +1118,7 @@ DEFUN(cfg_mgcp_osmux,
* allow to turn it on yet. */
vty_out(vty, "OSMUX currently unavailable in this software version.%s", VTY_NEWLINE);
return CMD_WARNING;
-
+#if 0
if (strcmp(argv[0], "on") == 0)
g_cfg->osmux = OSMUX_USAGE_ON;
else if (strcmp(argv[0], "only") == 0)
@@ -1114,6 +1130,7 @@ DEFUN(cfg_mgcp_osmux,
}
return CMD_SUCCESS;
+#endif
}
DEFUN(cfg_mgcp_osmux_ip,
@@ -1164,6 +1181,14 @@ DEFUN(cfg_mgcp_osmux_dummy,
return CMD_SUCCESS;
}
+DEFUN(cfg_mgcp_domain,
+ cfg_mgcp_domain_cmd,
+ "domain NAME", "domain\n" "qualified domain name\n")
+{
+ osmo_strlcpy(g_cfg->domain, argv[0], sizeof(g_cfg->domain));
+ return CMD_SUCCESS;
+}
+
int mgcp_vty_init(void)
{
install_element_ve(&show_mgcp_cmd);
@@ -1181,8 +1206,11 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_rtp_port_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_rtp_bind_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_rtp_no_bind_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_probing_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_probing_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
@@ -1222,6 +1250,7 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
+ install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
install_node(&trunk_node, config_write_trunk);
@@ -1251,18 +1280,6 @@ int mgcp_vty_init(void)
return 0;
}
-static int allocate_trunk(struct mgcp_trunk_config *trunk)
-{
- if (mgcp_endpoints_allocate(trunk) != 0) {
- LOGP(DLMGCP, LOGL_ERROR,
- "Failed to allocate %d endpoints on trunk %d.\n",
- trunk->number_endpoints, trunk->trunk_nr);
- return -1;
- }
-
- return 0;
-}
-
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
enum mgcp_role role)
{
@@ -1286,17 +1303,18 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
return -1;
}
- if (allocate_trunk(&g_cfg->trunk) != 0) {
+ if (mgcp_endpoints_allocate(&g_cfg->trunk) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "Failed to initialize the virtual trunk.\n");
+ "Failed to initialize the virtual trunk (%d endpoints)\n",
+ g_cfg->trunk.number_endpoints);
return -1;
}
llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
- if (allocate_trunk(trunk) != 0) {
+ if (mgcp_endpoints_allocate(trunk) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
- "Failed to initialize E1 trunk %d.\n",
- trunk->trunk_nr);
+ "Failed to initialize trunk %d (%d endpoints)\n",
+ trunk->trunk_nr, trunk->number_endpoints);
return -1;
}
}
diff --git a/src/osmo-bsc_mgcp/Makefile.am b/src/osmo-bsc_mgcp/Makefile.am
index 4529a33..e8a6f46 100644
--- a/src/osmo-bsc_mgcp/Makefile.am
+++ b/src/osmo-bsc_mgcp/Makefile.am
@@ -8,6 +8,7 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
$(LIBBCG729_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -24,6 +25,7 @@ osmo_bsc_mgcp_LDADD = \
$(top_builddir)/src/libosmo-legacy-mgcp/libosmo-legacy-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
$(LIBBCG729_LIBS) \
$(LIBRARY_GSM) \
$(NULL)
diff --git a/src/osmo-bsc_mgcp/mgcp_main.c b/src/osmo-bsc_mgcp/mgcp_main.c
index 48241a6..edb19a6 100644
--- a/src/osmo-bsc_mgcp/mgcp_main.c
+++ b/src/osmo-bsc_mgcp/mgcp_main.c
@@ -189,33 +189,33 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
int mgcp_vty_is_config_node(struct vty *vty, int node)
{
- switch (node) {
- case CONFIG_NODE:
- return 0;
+ switch (node) {
+ case CONFIG_NODE:
+ return 0;
- default:
- return 1;
- }
+ default:
+ return 1;
+ }
}
int mgcp_vty_go_parent(struct vty *vty)
{
- switch (vty->node) {
- case TRUNK_NODE:
- vty->node = MGCP_NODE;
- vty->index = NULL;
- break;
- case MGCP_NODE:
- default:
- if (mgcp_vty_is_config_node(vty, vty->node))
- vty->node = CONFIG_NODE;
- else
- vty->node = ENABLE_NODE;
-
- vty->index = NULL;
- }
-
- return vty->node;
+ switch (vty->node) {
+ case TRUNK_NODE:
+ vty->node = MGCP_NODE;
+ vty->index = NULL;
+ break;
+ case MGCP_NODE:
+ default:
+ if (mgcp_vty_is_config_node(vty, vty->node))
+ vty->node = CONFIG_NODE;
+ else
+ vty->node = ENABLE_NODE;
+
+ vty->index = NULL;
+ }
+
+ return vty->node;
}
@@ -231,8 +231,8 @@ static const struct log_info_cat log_categories[] = {
};
const struct log_info log_info = {
- .cat = log_categories,
- .num_cat = ARRAY_SIZE(log_categories),
+ .cat = log_categories,
+ .num_cat = ARRAY_SIZE(log_categories),
};
int main(int argc, char **argv)
@@ -244,7 +244,7 @@ int main(int argc, char **argv)
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
osmo_init_ignore_signals();
- osmo_init_logging(&log_info);
+ osmo_init_logging2(tall_bsc_ctx, &log_info);
cfg = mgcp_config_alloc();
if (!cfg)
@@ -282,8 +282,8 @@ int main(int argc, char **argv)
/* set some callbacks */
cfg->reset_cb = mgcp_rsip_cb;
- /* we need to bind a socket */
- if (rc == 0) {
+ /* we need to bind a socket */
+ if (rc == 0) {
cfg->gw_fd.bfd.when = BSC_FD_READ;
cfg->gw_fd.bfd.cb = read_call_agent;
cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
diff --git a/src/osmo-mgw/Makefile.am b/src/osmo-mgw/Makefile.am
index 0e12beb..a076d4c 100644
--- a/src/osmo-mgw/Makefile.am
+++ b/src/osmo-mgw/Makefile.am
@@ -8,6 +8,8 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -20,7 +22,9 @@ osmo_mgw_SOURCES = \
$(NULL)
osmo_mgw_LDADD = \
- $(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.la \
+ $(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(LIBOSMONETIF_LIBS) \
$(NULL)
diff --git a/src/osmo-mgw/mgw_main.c b/src/osmo-mgw/mgw_main.c
index ab54e62..de094c1 100644
--- a/src/osmo-mgw/mgw_main.c
+++ b/src/osmo-mgw/mgw_main.c
@@ -4,6 +4,7 @@
/*
* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
+ * (C) 2017 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -36,6 +37,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/vty.h>
#include <osmocom/mgcp/debug.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
@@ -44,12 +46,14 @@
#include <osmocom/core/stats.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/stats.h>
+#include <osmocom/vty/misc.h>
#include "../../bscconfig.h"
@@ -63,16 +67,16 @@ static struct mgcp_trunk_config *reset_trunk;
static int reset_endpoints = 0;
static int daemonize = 0;
-const char *openbsc_copyright =
+const char *osmomgw_copyright =
"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
"Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
- "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
- "Dieter Spaar, Andreas Eversberg, Harald Welte\r\n\r\n"
+ "Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
+ "Philipp Maier\r\n\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
-static char *config_file = "mgcp.cfg";
+static char *config_file = "osmo-mgw.cfg";
/* used by msgb and mgcp */
void *tall_bsc_ctx = NULL;
@@ -187,7 +191,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
/* Walk over all endpoints and trigger a release, this will release all
* endpoints, possible open connections are forcefully dropped */
for (i = 1; i < reset_trunk->number_endpoints; ++i)
- mgcp_release_endp(&reset_trunk->endpoints[i]);
+ mgcp_endp_release(&reset_trunk->endpoints[i]);
}
return 0;
@@ -195,33 +199,33 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
int mgcp_vty_is_config_node(struct vty *vty, int node)
{
- switch (node) {
- case CONFIG_NODE:
- return 0;
+ switch (node) {
+ case CONFIG_NODE:
+ return 0;
- default:
- return 1;
- }
+ default:
+ return 1;
+ }
}
int mgcp_vty_go_parent(struct vty *vty)
{
- switch (vty->node) {
- case TRUNK_NODE:
- vty->node = MGCP_NODE;
- vty->index = NULL;
- break;
- case MGCP_NODE:
- default:
- if (mgcp_vty_is_config_node(vty, vty->node))
- vty->node = CONFIG_NODE;
- else
- vty->node = ENABLE_NODE;
-
- vty->index = NULL;
- }
-
- return vty->node;
+ switch (vty->node) {
+ case TRUNK_NODE:
+ vty->node = MGCP_NODE;
+ vty->index = NULL;
+ break;
+ case MGCP_NODE:
+ default:
+ if (mgcp_vty_is_config_node(vty, vty->node))
+ vty->node = CONFIG_NODE;
+ else
+ vty->node = ENABLE_NODE;
+
+ vty->index = NULL;
+ }
+
+ return vty->node;
}
@@ -243,28 +247,31 @@ static const struct log_info_cat log_categories[] = {
};
const struct log_info log_info = {
- .cat = log_categories,
- .num_cat = ARRAY_SIZE(log_categories),
+ .cat = log_categories,
+ .num_cat = ARRAY_SIZE(log_categories),
};
int main(int argc, char **argv)
{
- struct sockaddr_in addr;
- int on = 1, rc;
+ unsigned int flags;
+ int rc;
tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
+ vty_info.tall_ctx = tall_bsc_ctx;
+
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
osmo_init_ignore_signals();
- osmo_init_logging(&log_info);
+ osmo_init_logging2(tall_bsc_ctx, &log_info);
cfg = mgcp_config_alloc();
if (!cfg)
return -1;
- vty_info.copyright = openbsc_copyright;
+ vty_info.copyright = osmomgw_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
+ osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds(&log_info);
mgcp_vty_init();
@@ -279,7 +286,7 @@ int main(int argc, char **argv)
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(tall_bsc_ctx, NULL,
- vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP);
+ vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
if (rc < 0)
return rc;
@@ -287,54 +294,29 @@ int main(int argc, char **argv)
* mgcp-command "RSIP" (Reset in Progress) is received */
cfg->reset_cb = mgcp_rsip_cb;
- /* we need to bind a socket */
- if (rc == 0) {
- cfg->gw_fd.bfd.when = BSC_FD_READ;
- cfg->gw_fd.bfd.cb = read_call_agent;
- cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (cfg->gw_fd.bfd.fd < 0) {
- perror("Gateway failed to listen");
- return -1;
- }
-
- setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(cfg->source_port);
- inet_aton(cfg->source_addr, &addr.sin_addr);
-
- if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("Gateway failed to bind");
- return -1;
- }
-
- cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
- if (!cfg->gw_fd.bfd.data) {
- fprintf(stderr, "Gateway memory error.\n");
- return -1;
- }
+ /* we need to bind a socket */
+ flags = OSMO_SOCK_F_BIND;
+ if (cfg->call_agent_addr)
+ flags |= OSMO_SOCK_F_CONNECT;
- if (cfg->call_agent_addr) {
- addr.sin_port = htons(2727);
- inet_aton(cfg->call_agent_addr, &addr.sin_addr);
- if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DLMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
- cfg->call_agent_addr, errno);
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
- }
-
- if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) {
- LOGP(DLMGCP, LOGL_FATAL, "Failed to register the fd\n");
- return -1;
- }
+ rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ cfg->source_addr, cfg->source_port,
+ cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
+ if (rc < 0) {
+ perror("Gateway failed to bind");
+ return -1;
+ }
- LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
+ cfg->gw_fd.bfd.cb = read_call_agent;
+ cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
+ if (!cfg->gw_fd.bfd.data) {
+ fprintf(stderr, "Gateway memory error.\n");
+ return -1;
}
+ LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP, listen on %s:%u\n",
+ cfg->source_addr, cfg->source_port);
+
/* initialisation */
srand(time(NULL));
diff --git a/tests/legacy_mgcp/mgcp_test.c b/tests/legacy_mgcp/mgcp_test.c
index 1400893..39400d4 100644
--- a/tests/legacy_mgcp/mgcp_test.c
+++ b/tests/legacy_mgcp/mgcp_test.c
@@ -268,7 +268,9 @@ static void test_strline(void)
"C: 2\r\n"
#define DLCX_RET "250 7 OK\r\n" \
- "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
+ "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
+
+ #define DLCX_RET_OSMUX DLCX_RET \
"X-Osmo-CP: EC TIS=0, TOS=0, TIR=0, TOR=0\r\n"
#define RQNT "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
@@ -1212,8 +1214,9 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
- msgb_talloc_ctx_init(NULL, 0);
- osmo_init_logging(&log_info);
+ void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
+ void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
+ osmo_init_logging2(ctx, &log_info);
test_strline();
test_values();
@@ -1231,6 +1234,9 @@ int main(int argc, char **argv)
test_no_name();
test_osmux_cid();
+ OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
+ OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
+ talloc_free(msgb_ctx);
printf("Done\n");
return EXIT_SUCCESS;
}
diff --git a/tests/legacy_mgcp/mgcp_transcoding_test.c b/tests/legacy_mgcp/mgcp_transcoding_test.c
index 61de25f..d3f94c7 100644
--- a/tests/legacy_mgcp/mgcp_transcoding_test.c
+++ b/tests/legacy_mgcp/mgcp_transcoding_test.c
@@ -588,7 +588,8 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
int rc;
- osmo_init_logging(&log_info);
+ void *ctx = talloc_named_const(NULL, 0, "mgcp_transcoding_test");
+ osmo_init_logging2(ctx, &log_info);
printf("=== Transcoding Good Cases ===\n");
diff --git a/tests/mgcp/Makefile.am b/tests/mgcp/Makefile.am
index caccb9f..df2b7c8 100644
--- a/tests/mgcp/Makefile.am
+++ b/tests/mgcp/Makefile.am
@@ -8,6 +8,8 @@ AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -29,9 +31,10 @@ mgcp_test_SOURCES = \
$(NULL)
mgcp_test_LDADD = \
- $(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.la \
+ $(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
-lm \
diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c
index e14b7ee..f6c421a 100644
--- a/tests/mgcp/mgcp_test.c
+++ b/tests/mgcp/mgcp_test.c
@@ -25,7 +25,7 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/mgcp_msg.h>
-#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
@@ -66,43 +66,41 @@ static void test_strline(void)
OSMO_ASSERT(counter == EXPECTED_NUMBER_OF_LINES);
}
-#define AUEP1 "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n"
+#define AUEP1 "AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
#define AUEP1_RET "200 158663169 OK\r\n"
-#define AUEP2 "AUEP 18983213 ds/e1-2/1@172.16.6.66 MGCP 1.0\r\n"
+#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
#define AUEP2_RET "500 18983213 FAIL\r\n"
#define EMPTY "\r\n"
#define EMPTY_RET NULL
#define SHORT "CRCX \r\n"
#define SHORT_RET "510 000000 FAIL\r\n"
-#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@172.16.6.66 MGCP 1.0\r\n"
-#define MDCX_ERR_RET "510 18983213 FAIL\r\n"
-#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n"
+#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
+#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
+#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
#define MDCX_RET "400 18983214 FAIL\r\n"
#define MDCX3 \
"MDCX 18983215 1@mgw MGCP 1.0\r\n" \
- "I: 1\n"
+ "I: %s\n"
#define MDCX3_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
- "m=audio 16002 RTP/AVP 128\r\n" \
- "a=rtpmap:128 GSM-EFR/8000\r\n" \
+ "m=audio 16002 RTP/AVP 97\r\n" \
+ "a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -112,15 +110,14 @@ static void test_strline(void)
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
- "m=audio 16006 RTP/AVP 128\r\n" \
- "a=rtpmap:128 GSM-EFR/8000\r\n" \
+ "m=audio 16006 RTP/AVP 97\r\n" \
+ "a=rtpmap:97 GSM-EFR/8000\r\n" \
"a=fmtp:126 0/1/2\r\n" \
"a=ptime:40\r\n"
@@ -128,11 +125,11 @@ static void test_strline(void)
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -141,10 +138,9 @@ static void test_strline(void)
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -154,10 +150,9 @@ static void test_strline(void)
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -169,11 +164,11 @@ static void test_strline(void)
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -184,11 +179,11 @@ static void test_strline(void)
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -199,11 +194,11 @@ static void test_strline(void)
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -214,11 +209,11 @@ static void test_strline(void)
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
@@ -229,7 +224,7 @@ static void test_strline(void)
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
#define SHORT2 "CRCX 1"
@@ -242,7 +237,6 @@ static void test_strline(void)
"CRCX 2 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
- "I: 1\r\n" \
"L: p:20\r\n" \
"\r\n" \
"v=0\r\n" \
@@ -253,10 +247,10 @@ static void test_strline(void)
#define CRCX_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "I: %s\r\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -266,10 +260,10 @@ static void test_strline(void)
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "I: %s\r\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -278,10 +272,10 @@ static void test_strline(void)
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "I: %s\r\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -294,7 +288,6 @@ static void test_strline(void)
"CRCX 2 1@mgw MGCP 1.0\r" \
"M: recvonly\r" \
"C: 2\r\n" \
- "I: 1\n" \
"\n" \
"v=0\r" \
"c=IN IP4 123.12.12.123\r" \
@@ -303,10 +296,10 @@ static void test_strline(void)
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
- "I: 1\n" \
- "\n" \
+ "I: %s\r\n" \
+ "\r\n" \
"v=0\r\n" \
- "o=- 1 23 IN IP4 0.0.0.0\r\n" \
+ "o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"t=0 0\r\n" \
@@ -316,12 +309,14 @@ static void test_strline(void)
#define DLCX \
"DLCX 7 1@mgw MGCP 1.0\r\n" \
- "I: 1\r\n" \
+ "I: %s\r\n" \
"C: 2\r\n"
#define DLCX_RET \
"250 7 OK\r\n" \
- "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
+ "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
+
+ #define DLCX_RET_OSMUX DLCX_RET \
"X-Osmo-CP: EC TI=0, TO=0\r\n"
#define RQNT \
@@ -343,7 +338,6 @@ static void test_strline(void)
#define CRCX_MULT_1 \
"CRCX 2 1@mgw MGCP 1.0\r\n" \
- "I: 4711\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -358,7 +352,6 @@ static void test_strline(void)
#define CRCX_MULT_2 \
"CRCX 2 2@mgw MGCP 1.0\r\n" \
- "I: 90210\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -374,7 +367,6 @@ static void test_strline(void)
#define CRCX_MULT_3 \
"CRCX 2 3@mgw MGCP 1.0\r\n" \
- "I: 0815\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -390,7 +382,6 @@ static void test_strline(void)
#define CRCX_MULT_4 \
"CRCX 2 4@mgw MGCP 1.0\r\n" \
- "I: 32168\r\n" \
"M: recvonly\r\n" \
"C: 2\r\n" \
"X\r\n" \
@@ -407,7 +398,6 @@ static void test_strline(void)
#define CRCX_MULT_GSM_EXACT \
"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
"C: 1355c6041e\r\n" \
- "I: 3\r\n" \
"L: p:20, a:GSM, nt:IN\r\n" \
"M: recvonly\r\n" \
"\r\n" \
@@ -432,7 +422,7 @@ static void test_strline(void)
#define MDCX_NAT_DUMMY \
"MDCX 23 5@mgw MGCP 1.0\r\n" \
"C: 1355c6041e\r\n" \
- "I: 3\r\n" \
+ "I: %s\r\n" \
"\r\n" \
"c=IN IP4 8.8.8.8\r\n" \
"m=audio 16434 RTP/AVP 255\r\n"
@@ -482,12 +472,20 @@ static const struct mgcp_test retransmit[] = {
{"DLCX", DLCX, DLCX_RET},
};
-static struct msgb *create_msg(const char *str)
+static struct msgb *create_msg(const char *str, const char *conn_id)
{
struct msgb *msg;
+ int len;
+
+ printf("creating message from statically defined input:\n");
+ printf("---------8<---------\n%s\n---------8<---------\n", str);
msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
- int len = sprintf((char *)msg->data, "%s", str);
+ if (conn_id && strlen(conn_id))
+ len = sprintf((char *)msg->data, str, conn_id, conn_id);
+ else
+ len = sprintf((char *)msg->data, "%s", str);
+
msg->l2h = msgb_put(msg, len);
return msg;
}
@@ -554,20 +552,111 @@ static void test_values(void)
MGCP_CONN_RECV_SEND);
}
+/* Extract a connection ID from a response (CRCX) */
+static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
+ unsigned int conn_id_len)
+{
+ char *conn_id_ptr;
+ int i;
+ bool got_conn_id = false;
+
+ /* First try to get the conn_id from the I: parameter */
+ conn_id_ptr = strstr((char *)resp, "I: ");
+ if (conn_id_ptr) {
+ memset(conn_id, 0, conn_id_len);
+ memcpy(conn_id, conn_id_ptr + 3, 32);
+ got_conn_id = true;
+ } else {
+ /* Alternatively try to extract the conn_id from the o=- SDP
+ * parameter */
+ conn_id_ptr = strstr((char *)resp, "o=- ");
+ if(conn_id_ptr) {
+ memset(conn_id, 0, conn_id_len);
+ memcpy(conn_id, conn_id_ptr + 4, 32);
+ got_conn_id = true;
+ }
+ }
+
+ if (got_conn_id) {
+ for (i = 0; i < conn_id_len; i++) {
+ if (conn_id[i] == '\n' || conn_id[i] == '\r')
+ conn_id[i] = '\0';
+ }
+
+ /* A valid conn_id must at least contain one digit, and must
+ * not exceed a length of 32 digits */
+ OSMO_ASSERT(strlen(conn_id) <= 32);
+ OSMO_ASSERT(strlen(conn_id) > 0);
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* Check response, automatically patch connection ID if needed */
+static int check_response(uint8_t *resp, const char *exp_resp)
+{
+ char exp_resp_patched[4096];
+ const char *exp_resp_ptr;
+ char conn_id[256];
+
+ printf("checking response:\n");
+
+ /* If the expected response is intened to be patched
+ * (%s placeholder inside) we will patch it with the
+ * connection identifier we just received from the
+ * real response. This is necessary because the CI
+ * is generated by the mgcp code on CRCX and we can
+ * not know it in advance */
+ if (strstr(exp_resp, "%s")) {
+ if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
+ 0) {
+ sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
+ exp_resp_ptr = exp_resp_patched;
+ printf
+ ("using message with patched conn_id for comparison\n");
+ } else {
+ printf
+ ("patching conn_id failed, using message as statically defined for comparison\n");
+ exp_resp_ptr = exp_resp;
+ }
+ } else {
+ printf("using message as statically defined for comparison\n");
+ exp_resp_ptr = exp_resp;
+ }
+
+ if (strcmp((char *)resp, exp_resp_ptr) != 0) {
+ printf("Unexpected response, please check!\n");
+ printf
+ ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
+ resp);
+ printf
+ ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
+ exp_resp_ptr);
+ return -EINVAL;
+ }
+
+ printf("Response matches our expectations.\n");
+ return 0;
+}
+
static void test_messages(void)
{
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
int i;
struct mgcp_conn_rtp *conn = NULL;
+ char last_conn_id[256];
+ int rc;
cfg = mgcp_config_alloc();
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
-
cfg->policy_cb = mgcp_test_policy_cb;
+ memset(last_conn_id, 0, sizeof(last_conn_id));
+
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
for (i = 0; i < ARRAY_SIZE(tests); i++) {
@@ -575,6 +664,7 @@ static void test_messages(void)
struct msgb *inp;
struct msgb *msg;
+ printf("\n================================================\n");
printf("Testing %s\n", t->name);
last_endpoint = -1;
@@ -583,7 +673,7 @@ static void test_messages(void)
osmo_talloc_replace_string(cfg, &cfg->trunk.audio_fmtp_extra,
t->extra_fmtp);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
if (!t->exp_resp) {
@@ -592,12 +682,22 @@ static void test_messages(void)
(char *)msg->data);
OSMO_ASSERT(false);
}
- } else if (strcmp((char *)msg->data, t->exp_resp) != 0) {
- printf("%s failed.\nExpected:\n%s\nGot:\n%s\n",
- t->name, t->exp_resp, (char *) msg->data);
+ } else if (check_response(msg->data, t->exp_resp) != 0) {
+ printf("%s failed.\n", t->name);
OSMO_ASSERT(false);
}
- msgb_free(msg);
+
+ if (msg) {
+ rc = get_conn_id_from_response(msg->data, last_conn_id,
+ sizeof(last_conn_id));
+ if (rc)
+ printf("(response contains a connection id)\n");
+ else
+ printf("(response does not contain a connection id)\n");
+ }
+
+ if (msg)
+ msgb_free(msg);
if (dummy_packets)
printf("Dummy packets: %d\n", dummy_packets);
@@ -605,7 +705,7 @@ static void test_messages(void)
if (last_endpoint != -1) {
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 1);
+ conn = mgcp_conn_get_rtp(endp, "1");
if (conn) {
OSMO_ASSERT(conn);
@@ -657,7 +757,7 @@ static void test_messages(void)
}
/* Check detected payload type */
- if (t->ptype != PTYPE_IGNORE) {
+ if (conn && t->ptype != PTYPE_IGNORE) {
OSMO_ASSERT(last_endpoint != -1);
endp = &cfg->trunk.endpoints[last_endpoint];
@@ -682,12 +782,16 @@ static void test_retransmission(void)
{
struct mgcp_config *cfg;
int i;
+ char last_conn_id[256];
+ int rc;
cfg = mgcp_config_alloc();
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
+ memset(last_conn_id, 0, sizeof(last_conn_id));
+
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
@@ -695,24 +799,33 @@ static void test_retransmission(void)
struct msgb *inp;
struct msgb *msg;
+ printf("\n================================================\n");
printf("Testing %s\n", t->name);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
- if (strcmp((char *)msg->data, t->exp_resp) != 0) {
+ if (msg && check_response(msg->data, t->exp_resp) != 0) {
printf("%s failed '%s'\n", t->name, (char *)msg->data);
OSMO_ASSERT(false);
}
- msgb_free(msg);
+
+ if (msg && strcmp(t->name, "CRCX") == 0) {
+ rc = get_conn_id_from_response(msg->data, last_conn_id,
+ sizeof(last_conn_id));
+ OSMO_ASSERT(rc == 0);
+ }
+
+ if (msg)
+ msgb_free(msg);
/* Retransmit... */
printf("Re-transmitting %s\n", t->name);
- inp = create_msg(t->req);
+ inp = create_msg(t->req, last_conn_id);
msg = mgcp_handle_message(cfg, inp);
msgb_free(inp);
- if (strcmp((char *)msg->data, t->exp_resp) != 0) {
+ if (check_response(msg->data, t->exp_resp) != 0) {
printf("%s failed '%s'\n", t->name, (char *)msg->data);
OSMO_ASSERT(false);
}
@@ -733,21 +846,26 @@ static void test_rqnt_cb(void)
{
struct mgcp_config *cfg;
struct msgb *inp, *msg;
+ char conn_id[256];
cfg = mgcp_config_alloc();
cfg->rqnt_cb = rqnt_cb;
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
- inp = create_msg(CRCX);
- msgb_free(mgcp_handle_message(cfg, inp));
+ inp = create_msg(CRCX, NULL);
+ msg = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(msg);
+ OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
+ sizeof(conn_id)) == 0);
+ msgb_free(msg);
msgb_free(inp);
/* send the RQNT and check for the CB */
- inp = create_msg(RQNT);
+ inp = create_msg(RQNT, conn_id);
msg = mgcp_handle_message(cfg, inp);
if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
printf("FAILED: message is not 200. '%s'\n", msg->l2h);
@@ -762,7 +880,7 @@ static void test_rqnt_cb(void)
msgb_free(msg);
msgb_free(inp);
- inp = create_msg(DLCX);
+ inp = create_msg(DLCX, conn_id);
msgb_free(mgcp_handle_message(cfg, inp));
msgb_free(inp);
talloc_free(cfg);
@@ -809,12 +927,12 @@ static void test_packet_loss_calc(void)
memset(&state, 0, sizeof(state));
memset(&rtp, 0, sizeof(rtp));
- state.stats_initialized = 1;
- state.stats_base_seq = pl_test_dat[i].base_seq;
- state.stats_max_seq = pl_test_dat[i].max_seq;
- state.stats_cycles = pl_test_dat[i].cycles;
+ state.stats.initialized = 1;
+ state.stats.base_seq = pl_test_dat[i].base_seq;
+ state.stats.max_seq = pl_test_dat[i].max_seq;
+ state.stats.cycles = pl_test_dat[i].cycles;
- rtp.packets_rx = pl_test_dat[i].packets;
+ rtp.stats.packets_rx = pl_test_dat[i].packets;
calc_loss(&state, &rtp, &expected, &loss);
if (loss != pl_test_dat[i].loss
@@ -865,7 +983,7 @@ static void test_mgcp_stats(void)
int loss;
int rc;
- msg = create_msg(DLCX_RET);
+ msg = create_msg(DLCX_RET, NULL);
rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
printf("Parsing result: %d\n", rc);
if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
@@ -875,7 +993,7 @@ static void test_mgcp_stats(void)
msg =
create_msg
- ("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n");
+ ("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n", NULL);
rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
printf("Parsing result: %d\n", rc);
if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
@@ -1014,6 +1132,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
int last_in_ts_err_cnt = 0;
int last_out_ts_err_cnt = 0;
struct mgcp_conn_rtp *conn = NULL;
+ struct mgcp_conn *_conn = NULL;
printf("Testing packet error detection%s%s.\n",
patch_ssrc ? ", patch SSRC" : "",
@@ -1025,7 +1144,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
endp.type = &ep_typeset.rtp;
- trunk.number_endpoints = 1;
+ trunk.vty_number_endpoints = 1;
trunk.endpoints = &endp;
trunk.force_constant_ssrc = patch_ssrc;
trunk.force_aligned_timing = patch_ts;
@@ -1033,9 +1152,10 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
endp.tcfg = &trunk;
INIT_LLIST_HEAD(&endp.conns);
- mgcp_conn_alloc(NULL, &endp, 4711, MGCP_CONN_TYPE_RTP,
- "test-connection");
- conn = mgcp_conn_get_rtp(&endp, 4711);
+ _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
+ "test-connection");
+ OSMO_ASSERT(_conn);
+ conn = mgcp_conn_get_rtp(&endp, _conn->id);
OSMO_ASSERT(conn);
rtp = &conn->end;
@@ -1074,7 +1194,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
state.out_stream.err_ts_counter - last_out_ts_err_cnt);
printf("Stats: Jitter = %u, Transit = %d\n",
- calc_jitter(&state), state.stats_transit);
+ calc_jitter(&state), state.stats.transit);
last_in_ts_err_cnt = state.in_stream.err_ts_counter;
last_out_ts_err_cnt = state.out_stream.err_ts_counter;
@@ -1083,6 +1203,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
}
force_monotonic_time_us = -1;
+ mgcp_conn_free_all(&endp);
}
static void test_multilple_codec(void)
@@ -1092,96 +1213,107 @@ static void test_multilple_codec(void)
struct msgb *inp, *resp;
struct in_addr addr;
struct mgcp_conn_rtp *conn = NULL;
+ char conn_id[256];
printf("Testing multiple payload types\n");
cfg = mgcp_config_alloc();
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
cfg->policy_cb = mgcp_test_policy_cb;
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
/* Allocate endpoint 1@mgw with two codecs */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_1);
+ inp = create_msg(CRCX_MULT_1, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 1);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 4711);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 97);
/* Allocate 2@mgw with three codecs, last one ignored */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_2);
+ inp = create_msg(CRCX_MULT_2, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 2);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 90210);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 97);
/* Allocate 3@mgw with no codecs, check for PT == -1 */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_3);
+ inp = create_msg(CRCX_MULT_3, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 3);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 815);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == -1);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
/* Allocate 4@mgw with a single codec */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_4);
+ inp = create_msg(CRCX_MULT_4, NULL);
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 4);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 32168);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 18);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
/* Allocate 5@mgw at select GSM.. */
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_GSM_EXACT);
+ inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
talloc_free(cfg->trunk.audio_name);
cfg->trunk.audio_name = "GSM/8000";
cfg->trunk.no_audio_transcoding = 1;
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 3);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 3);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
- inp = create_msg(MDCX_NAT_DUMMY);
+ inp = create_msg(MDCX_NAT_DUMMY, conn_id);
last_endpoint = -1;
resp = mgcp_handle_message(cfg, inp);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 3);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 3);
OSMO_ASSERT(conn->end.alt_codec.payload_type == -1);
@@ -1194,23 +1326,25 @@ static void test_multilple_codec(void)
/* Free the previous endpoint and the data and
* check if the connection really vanished... */
- mgcp_release_endp(endp);
+ mgcp_endp_release(endp);
talloc_free(endp->last_response);
talloc_free(endp->last_trans);
endp->last_response = endp->last_trans = NULL;
- conn = mgcp_conn_get_rtp(endp, 3);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(!conn);
last_endpoint = -1;
- inp = create_msg(CRCX_MULT_GSM_EXACT);
+ inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
cfg->trunk.no_audio_transcoding = 0;
resp = mgcp_handle_message(cfg, inp);
+ OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
+ sizeof(conn_id)) == 0);
msgb_free(inp);
msgb_free(resp);
OSMO_ASSERT(last_endpoint == 5);
endp = &cfg->trunk.endpoints[last_endpoint];
- conn = mgcp_conn_get_rtp(endp, 3);
+ conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec.payload_type == 255);
OSMO_ASSERT(conn->end.alt_codec.payload_type == 0);
@@ -1223,44 +1357,47 @@ static void test_no_cycle(void)
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
struct mgcp_conn_rtp *conn = NULL;
+ struct mgcp_conn *_conn = NULL;
printf("Testing no sequence flow on initial packet\n");
cfg = mgcp_config_alloc();
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
mgcp_endpoints_allocate(&cfg->trunk);
endp = &cfg->trunk.endpoints[1];
- mgcp_conn_alloc(NULL, endp, 4711, MGCP_CONN_TYPE_RTP,
- "test-connection");
- conn = mgcp_conn_get_rtp(endp, 4711);
+ _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
+ "test-connection");
+ OSMO_ASSERT(_conn);
+ conn = mgcp_conn_get_rtp(endp, _conn->id);
OSMO_ASSERT(conn);
- OSMO_ASSERT(conn->state.stats_initialized == 0);
+ OSMO_ASSERT(conn->state.stats.initialized == 0);
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
- OSMO_ASSERT(conn->state.stats_initialized == 1);
- OSMO_ASSERT(conn->state.stats_cycles == 0);
- OSMO_ASSERT(conn->state.stats_max_seq == 0);
+ OSMO_ASSERT(conn->state.stats.initialized == 1);
+ OSMO_ASSERT(conn->state.stats.cycles == 0);
+ OSMO_ASSERT(conn->state.stats.max_seq == 0);
mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
- OSMO_ASSERT(conn->state.stats_initialized == 1);
- OSMO_ASSERT(conn->state.stats_cycles == 0);
- OSMO_ASSERT(conn->state.stats_max_seq == 1);
+ OSMO_ASSERT(conn->state.stats.initialized == 1);
+ OSMO_ASSERT(conn->state.stats.cycles == 0);
+ OSMO_ASSERT(conn->state.stats.max_seq == 1);
/* now jump.. */
mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
- OSMO_ASSERT(conn->state.stats_initialized == 1);
- OSMO_ASSERT(conn->state.stats_cycles == 0);
- OSMO_ASSERT(conn->state.stats_max_seq == UINT16_MAX);
+ OSMO_ASSERT(conn->state.stats.initialized == 1);
+ OSMO_ASSERT(conn->state.stats.cycles == 0);
+ OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
/* and wrap */
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
- OSMO_ASSERT(conn->state.stats_initialized == 1);
- OSMO_ASSERT(conn->state.stats_cycles == UINT16_MAX + 1);
- OSMO_ASSERT(conn->state.stats_max_seq == 0);
+ OSMO_ASSERT(conn->state.stats.initialized == 1);
+ OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
+ OSMO_ASSERT(conn->state.stats.max_seq == 0);
+ mgcp_endp_release(endp);
talloc_free(cfg);
}
@@ -1272,7 +1409,7 @@ static void test_no_name(void)
printf("Testing no rtpmap name\n");
cfg = mgcp_config_alloc();
- cfg->trunk.number_endpoints = 64;
+ cfg->trunk.vty_number_endpoints = 64;
cfg->trunk.audio_send_name = 0;
mgcp_endpoints_allocate(&cfg->trunk);
@@ -1280,9 +1417,10 @@ static void test_no_name(void)
mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
- inp = create_msg(CRCX);
+ inp = create_msg(CRCX, NULL);
msg = mgcp_handle_message(cfg, inp);
- if (strcmp((char *)msg->data, CRCX_RET_NO_RTPMAP) != 0) {
+
+ if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
printf("FAILED: there should not be a RTPMAP: %s\n",
(char *)msg->data);
OSMO_ASSERT(false);
@@ -1290,7 +1428,7 @@ static void test_no_name(void)
msgb_free(inp);
msgb_free(msg);
- mgcp_release_endp(&cfg->trunk.endpoints[1]);
+ mgcp_endp_release(&cfg->trunk.endpoints[1]);
talloc_free(cfg);
}
@@ -1329,8 +1467,9 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
- msgb_talloc_ctx_init(NULL, 0);
- osmo_init_logging(&log_info);
+ void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
+ void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
+ osmo_init_logging2(ctx, &log_info);
test_strline();
test_values();
@@ -1348,6 +1487,9 @@ int main(int argc, char **argv)
test_no_name();
test_osmux_cid();
+ OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
+ OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
+ talloc_free(msgb_ctx);
printf("Done\n");
return EXIT_SUCCESS;
}
diff --git a/tests/mgcp/mgcp_test.ok b/tests/mgcp/mgcp_test.ok
index 7376930..d2879ad 100644
--- a/tests/mgcp/mgcp_test.ok
+++ b/tests/mgcp/mgcp_test.ok
@@ -11,87 +11,573 @@ line: 'mixed (4 lines)'
line: ''
line: ''
line: ''
+
+================================================
Testing AUEP1
+creating message from statically defined input:
+---------8<---------
+AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing AUEP2
+creating message from statically defined input:
+---------8<---------
+AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing MDCX1
+creating message from statically defined input:
+---------8<---------
+MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing MDCX2
+creating message from statically defined input:
+---------8<---------
+MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing CRCX
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 1: RECV
+
+================================================
Testing MDCX3
+creating message from statically defined input:
+---------8<---------
+MDCX 18983215 1@mgw MGCP 1.0
+I: %s
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetization period not set
-Connection mode: 1: RECV
+
+================================================
Testing MDCX4
+creating message from statically defined input:
+---------8<---------
+MDCX 18983216 1@mgw MGCP 1.0
+M: sendrecv C: 2
+I: %s
+L: p:20, a:AMR, nt:IN
+
+v=0
+o=- %s 23 IN IP4 0.0.0.0
+c=IN IP4 0.0.0.0
+t=0 0
+m=audio 4441 RTP/AVP 99
+a=rtpmap:99 AMR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 3: SEND RECV
+
+================================================
Testing MDCX4_PT1
+creating message from statically defined input:
+---------8<---------
+MDCX 18983217 1@mgw MGCP 1.0
+M: sendrecv C: 2
+I: %s
+L: p:20-40, a:AMR, nt:IN
+
+v=0
+o=- %s 23 IN IP4 0.0.0.0
+c=IN IP4 0.0.0.0
+t=0 0
+m=audio 4441 RTP/AVP 99
+a=rtpmap:99 AMR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-40
-Connection mode: 3: SEND RECV
+
+================================================
Testing MDCX4_PT2
+creating message from statically defined input:
+---------8<---------
+MDCX 18983218 1@mgw MGCP 1.0
+M: sendrecv C: 2
+I: %s
+L: p:20-20, a:AMR, nt:IN
+
+v=0
+o=- %s 23 IN IP4 0.0.0.0
+c=IN IP4 0.0.0.0
+t=0 0
+m=audio 4441 RTP/AVP 99
+a=rtpmap:99 AMR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 3: SEND RECV
+
+================================================
Testing MDCX4_PT3
+creating message from statically defined input:
+---------8<---------
+MDCX 18983219 1@mgw MGCP 1.0
+M: sendrecv C: 2
+I: %s
+L: a:AMR, nt:IN
+
+v=0
+o=- %s 23 IN IP4 0.0.0.0
+c=IN IP4 0.0.0.0
+t=0 0
+m=audio 4441 RTP/AVP 99
+a=rtpmap:99 AMR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetization period not set
-Connection mode: 3: SEND RECV
+
+================================================
Testing MDCX4_SO
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 2: SEND
+creating message from statically defined input:
+---------8<---------
+MDCX 18983220 1@mgw MGCP 1.0
+M: sendonly C: 2
+I: %s
+L: p:20, a:AMR, nt:IN
+
+v=0
+o=- %s 23 IN IP4 0.0.0.0
+c=IN IP4 0.0.0.0
+t=0 0
+m=audio 4441 RTP/AVP 99
+a=rtpmap:99 AMR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
+
+================================================
Testing MDCX4_RO
+creating message from statically defined input:
+---------8<---------
+MDCX 18983221 1@mgw MGCP 1.0
+M: recvonly C: 2
+I: %s
+L: p:20, a:AMR, nt:IN
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 1: RECV
+
+================================================
Testing DLCX
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing CRCX_ZYN
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0 M: recvonly C: 2
+
+v=0 c=IN IP4 123.12.12.123 m=audio 5904 RTP/AVP 97 a=rtpmap:97 GSM-EFR/8000
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 20
-Requested packetization period not set
-Connection mode: 1: RECV
+
+================================================
Testing EMPTY
+creating message from statically defined input:
+---------8<---------
+
+
+---------8<---------
+
+================================================
Testing SHORT1
+creating message from statically defined input:
+---------8<---------
+CRCX
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing SHORT2
+creating message from statically defined input:
+---------8<---------
+CRCX 1
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing SHORT3
+creating message from statically defined input:
+---------8<---------
+CRCX 1 1@mgw
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing SHORT4
+creating message from statically defined input:
+---------8<---------
+CRCX 1 1@mgw MGCP
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing RQNT1
+creating message from statically defined input:
+---------8<---------
+RQNT 186908780 1@mgw MGCP 1.0
+X: B244F267488
+S: D/9
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing RQNT2
+creating message from statically defined input:
+---------8<---------
+RQNT 186908781 1@mgw MGCP 1.0
+X: ADD4F26746F
+R: D/[0-9#*](N), G/ft, fxr/t38
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing DLCX
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing CRCX
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetetization period: 20-20
-Connection mode: 1: RECV
+
+================================================
Testing MDCX3
+creating message from statically defined input:
+---------8<---------
+MDCX 18983215 1@mgw MGCP 1.0
+I: %s
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+(response does not contain a connection id)
Dummy packets: 2
-Detected packet duration: 40
-Requested packetization period not set
-Connection mode: 1: RECV
+
+================================================
Testing DLCX
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+(response contains a connection id)
+
+================================================
Testing CRCX
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
Re-transmitting CRCX
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+
+================================================
Testing RQNT1
+creating message from statically defined input:
+---------8<---------
+RQNT 186908780 1@mgw MGCP 1.0
+X: B244F267488
+S: D/9
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
Re-transmitting RQNT1
+creating message from statically defined input:
+---------8<---------
+RQNT 186908780 1@mgw MGCP 1.0
+X: B244F267488
+S: D/9
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+
+================================================
Testing RQNT2
+creating message from statically defined input:
+---------8<---------
+RQNT 186908781 1@mgw MGCP 1.0
+X: ADD4F26746F
+R: D/[0-9#*](N), G/ft, fxr/t38
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
Re-transmitting RQNT2
+creating message from statically defined input:
+---------8<---------
+RQNT 186908781 1@mgw MGCP 1.0
+X: ADD4F26746F
+R: D/[0-9#*](N), G/ft, fxr/t38
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
+
+================================================
Testing MDCX3
+creating message from statically defined input:
+---------8<---------
+MDCX 18983215 1@mgw MGCP 1.0
+I: %s
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
Re-transmitting MDCX3
+creating message from statically defined input:
+---------8<---------
+MDCX 18983215 1@mgw MGCP 1.0
+I: %s
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
+
+================================================
Testing DLCX
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
Re-transmitting DLCX
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
+checking response:
+using message as statically defined for comparison
+Response matches our expectations.
Testing packet loss calculation.
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+RQNT 186908780 1@mgw MGCP 1.0
+X: B244F267488
+S: D/9
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+DLCX 7 1@mgw MGCP 1.0
+I: %s
+C: 2
+
+---------8<---------
Testing stat parsing
+creating message from statically defined input:
+---------8<---------
+250 7 OK
+P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0
+
+---------8<---------
Parsing result: 0
+creating message from statically defined input:
+---------8<---------
+250 7 OK
+P: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40
+
+---------8<---------
Parsing result: 0
Testing packet error detection, patch SSRC.
Output SSRC changed to 11223344
@@ -466,6 +952,156 @@ In TS: 160320, dTS: 160, Seq: 1002
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
Testing multiple payload types
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+X
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 18 97
+a=rtpmap:18 G729/8000
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+CRCX 2 2@mgw MGCP 1.0
+M: recvonly
+C: 2
+X
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 18 97 101
+a=rtpmap:18 G729/8000
+a=rtpmap:97 GSM-EFR/8000
+a=rtpmap:101 FOO/8000
+a=ptime:40
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+CRCX 2 3@mgw MGCP 1.0
+M: recvonly
+C: 2
+X
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP
+a=rtpmap:18 G729/8000
+a=rtpmap:97 GSM-EFR/8000
+a=rtpmap:101 FOO/8000
+a=ptime:40
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+CRCX 2 4@mgw MGCP 1.0
+M: recvonly
+C: 2
+X
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 18
+a=rtpmap:18 G729/8000
+a=rtpmap:97 GSM-EFR/8000
+a=rtpmap:101 FOO/8000
+a=ptime:40
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+CRCX 259260421 5@mgw MGCP 1.0
+C: 1355c6041e
+L: p:20, a:GSM, nt:IN
+M: recvonly
+
+v=0
+o=- 1439038275 1439038275 IN IP4 192.168.181.247
+s=-
+c=IN IP4 192.168.181.247
+t=0 0
+m=audio 29084 RTP/AVP 255 0 8 3 18 4 96 97 101
+a=rtpmap:0 PCMU/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:3 gsm/8000
+a=rtpmap:18 G729/8000
+a=fmtp:18 annexb=no
+a=rtpmap:4 G723/8000
+a=rtpmap:96 iLBC/8000
+a=fmtp:96 mode=20
+a=rtpmap:97 iLBC/8000
+a=fmtp:97 mode=30
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=recvonly
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+MDCX 23 5@mgw MGCP 1.0
+C: 1355c6041e
+I: %s
+
+c=IN IP4 8.8.8.8
+m=audio 16434 RTP/AVP 255
+
+---------8<---------
+creating message from statically defined input:
+---------8<---------
+CRCX 259260421 5@mgw MGCP 1.0
+C: 1355c6041e
+L: p:20, a:GSM, nt:IN
+M: recvonly
+
+v=0
+o=- 1439038275 1439038275 IN IP4 192.168.181.247
+s=-
+c=IN IP4 192.168.181.247
+t=0 0
+m=audio 29084 RTP/AVP 255 0 8 3 18 4 96 97 101
+a=rtpmap:0 PCMU/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:3 gsm/8000
+a=rtpmap:18 G729/8000
+a=fmtp:18 annexb=no
+a=rtpmap:4 G723/8000
+a=rtpmap:96 iLBC/8000
+a=fmtp:96 mode=20
+a=rtpmap:97 iLBC/8000
+a=fmtp:97 mode=30
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=recvonly
+
+---------8<---------
Testing no sequence flow on initial packet
Testing no rtpmap name
+creating message from statically defined input:
+---------8<---------
+CRCX 2 1@mgw MGCP 1.0
+M: recvonly
+C: 2
+L: p:20
+
+v=0
+c=IN IP4 123.12.12.123
+m=audio 5904 RTP/AVP 97
+a=rtpmap:97 GSM-EFR/8000
+a=ptime:40
+
+---------8<---------
+checking response:
+using message with patched conn_id for comparison
+Response matches our expectations.
Done
diff --git a/tests/mgcp_client/Makefile.am b/tests/mgcp_client/Makefile.am
index 5cd0d8a..5ce9538 100644
--- a/tests/mgcp_client/Makefile.am
+++ b/tests/mgcp_client/Makefile.am
@@ -37,3 +37,6 @@ mgcp_client_test_LDADD = \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
$(NULL)
+
+update_exp:
+ $(builddir)/mgcp_client_test >$(srcdir)/mgcp_client_test.ok 2>$(srcdir)/mgcp_client_test.err
diff --git a/tests/mgcp_client/mgcp_client_test.c b/tests/mgcp_client/mgcp_client_test.c
index 513f345..007b90c 100644
--- a/tests/mgcp_client/mgcp_client_test.c
+++ b/tests/mgcp_client/mgcp_client_test.c
@@ -18,12 +18,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
#include <string.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/application.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
+#include <errno.h>
void *ctx;
@@ -46,14 +49,14 @@ static struct msgb *mgcp_from_str(const char *head, const char *params)
l = strlen(head);
msg->l2h = msgb_put(msg, l);
data = (char*)msgb_l2(msg);
- strncpy(data, head, l);
+ osmo_strlcpy(data, head, l);
data = (char*)msgb_put(msg, 1);
*data = '\n';
l = strlen(params);
data = (char*)msgb_put(msg, l);
- strncpy(data, params, l);
+ osmo_strlcpy(data, params, l);
return msg;
}
@@ -66,14 +69,14 @@ static struct msgb *from_str(const char *str)
char *data;
msg->l2h = msgb_put(msg, l);
data = (char*)msgb_l2(msg);
- strncpy(data, str, l);
+ osmo_strlcpy(data, str, l);
return msg;
}
static struct mgcp_client_conf conf;
struct mgcp_client *mgcp = NULL;
-static void reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
+static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
int conn_id, const char *params)
{
static char compose[4096 - 128];
@@ -87,7 +90,7 @@ static void reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
printf("composed response:\n-----\n%s\n-----\n",
compose);
- mgcp_client_rx(mgcp, from_str(compose));
+ return mgcp_client_rx(mgcp, from_str(compose));
}
void test_response_cb(struct mgcp_response *response, void *priv)
@@ -162,7 +165,7 @@ void test_mgcp_msg(void)
.endpoint = "23@mgw",
.audio_port = 1234,
.call_id = 47,
- .conn_id = 11,
+ .conn_id = "11",
.conn_mode = MGCP_CONN_RECV_SEND
};
@@ -225,6 +228,154 @@ void test_mgcp_msg(void)
msgb_free(msg);
}
+void test_mgcp_client_cancel()
+{
+ mgcp_trans_id_t trans_id;
+ struct msgb *msg;
+ struct mgcp_msg mgcp_msg = {
+ .verb = MGCP_VERB_CRCX,
+ .audio_ip = "192.168.100.23",
+ .endpoint = "23@mgw",
+ .audio_port = 1234,
+ .call_id = 47,
+ .conn_id = "11",
+ .conn_mode = MGCP_CONN_RECV_SEND,
+ .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
+ | MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
+ };
+
+ printf("\n%s():\n", __func__);
+ fprintf(stderr, "\n%s():\n", __func__);
+
+ if (mgcp)
+ talloc_free(mgcp);
+ mgcp = mgcp_client_init(ctx, &conf);
+
+ msg = mgcp_msg_gen(mgcp, &mgcp_msg);
+ trans_id = mgcp_msg_trans_id(msg);
+ fprintf(stderr, "- composed msg with trans_id=%u\n", trans_id);
+
+ fprintf(stderr, "- not in queue yet, cannot cancel yet\n");
+ OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == -ENOENT);
+
+ fprintf(stderr, "- enqueue\n");
+ dummy_mgcp_send(msg);
+
+ fprintf(stderr, "- cancel succeeds\n");
+ OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == 0);
+
+ fprintf(stderr, "- late response gets discarded\n");
+ OSMO_ASSERT(reply_to(trans_id, 200, "OK", 1, "v=0\r\n") == -ENOENT);
+
+ fprintf(stderr, "- canceling again does nothing\n");
+ OSMO_ASSERT(mgcp_client_cancel(mgcp, trans_id) == -ENOENT);
+
+ fprintf(stderr, "%s() done\n", __func__);
+}
+
+struct sdp_section_start_test {
+ const char *body;
+ int expect_rc;
+ struct mgcp_response expect_params;
+};
+
+static struct sdp_section_start_test sdp_section_start_tests[] = {
+ {
+ .body = "",
+ .expect_rc = -EINVAL,
+ },
+ {
+ .body = "\n\n",
+ },
+ {
+ .body = "\r\n\r\n",
+ },
+ {
+ .body = "\n\r\n\r",
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\n\n"
+ "m=audio 23\r\n",
+ .expect_params = {
+ .audio_port = 23,
+ },
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\r\n\r\n"
+ "m=audio 23\r\n",
+ .expect_params = {
+ .audio_port = 23,
+ },
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\n\r\n\r"
+ "m=audio 23\r\n",
+ .expect_params = {
+ .audio_port = 23,
+ },
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\n\r\n"
+ "m=audio 23\r\n",
+ .expect_rc = -EINVAL,
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\r\n\r"
+ "m=audio 23\r\n",
+ .expect_rc = -EINVAL,
+ },
+ {
+ .body = "some mgcp header data\r\nand header params"
+ "\n\r\r"
+ "m=audio 23\r\n",
+ .expect_rc = -EINVAL,
+ },
+};
+
+void test_sdp_section_start()
+{
+ int i;
+ int failures = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sdp_section_start_tests); i++) {
+ int rc;
+ struct sdp_section_start_test *t = &sdp_section_start_tests[i];
+ struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
+
+ r->body = talloc_strdup(r, t->body);
+
+ printf("\n%s() test [%d]:\n", __func__, i);
+ fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
+ fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
+
+ rc = mgcp_response_parse_params(r);
+
+ fprintf(stderr, "got rc=%d\n", rc);
+ if (rc != t->expect_rc) {
+ fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
+ failures++;
+ }
+ if (rc) {
+ talloc_free(r);
+ continue;
+ }
+
+ fprintf(stderr, "got audio_port=%u\n", t->expect_params.audio_port);
+ if (r->audio_port != t->expect_params.audio_port) {
+ fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
+ failures++;
+ }
+ talloc_free(r);
+ }
+
+ OSMO_ASSERT(!failures);
+}
+
static const struct log_info_cat log_categories[] = {
};
@@ -238,16 +389,20 @@ int main(int argc, char **argv)
{
ctx = talloc_named_const(NULL, 1, "mgcp_client_test");
msgb_talloc_ctx_init(ctx, 0);
- osmo_init_logging(&log_info);
+ osmo_init_logging2(ctx, &log_info);
log_set_print_filename(osmo_stderr_target, 0);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
+ log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
+
mgcp_client_conf_init(&conf);
test_crcx();
test_mgcp_msg();
+ test_mgcp_client_cancel();
+ test_sdp_section_start();
printf("Done\n");
fprintf(stderr, "Done\n");
diff --git a/tests/mgcp_client/mgcp_client_test.err b/tests/mgcp_client/mgcp_client_test.err
index 24151ee..7309242 100644
--- a/tests/mgcp_client/mgcp_client_test.err
+++ b/tests/mgcp_client/mgcp_client_test.err
@@ -1,2 +1,65 @@
DLMGCP message buffer to small, can not generate MGCP message
+
+test_mgcp_client_cancel():
+- composed msg with trans_id=1
+- not in queue yet, cannot cancel yet
+DLMGCP Cannot cancel, no such transaction: 1
+- enqueue
+- cancel succeeds
+DLMGCP Canceled transaction 1
+- late response gets discarded
+DLMGCP Cannot find matching MGCP transaction for trans_id 1
+- canceling again does nothing
+DLMGCP Cannot cancel, no such transaction: 1
+test_mgcp_client_cancel() done
+
+test_sdp_section_start() test [0]:
+body: ""
+DLMGCP MGCP response: cannot find start of SDP parameters
+got rc=-22
+
+test_sdp_section_start() test [1]:
+body: "\n\n"
+got rc=0
+got audio_port=0
+
+test_sdp_section_start() test [2]:
+body: "\r\n\r\n"
+got rc=0
+got audio_port=0
+
+test_sdp_section_start() test [3]:
+body: "\n\r\n\r"
+got rc=0
+got audio_port=0
+
+test_sdp_section_start() test [4]:
+body: "some mgcp header data\r\nand header params\n\nm=audio 23\r\n"
+got rc=0
+got audio_port=23
+
+test_sdp_section_start() test [5]:
+body: "some mgcp header data\r\nand header params\r\n\r\nm=audio 23\r\n"
+got rc=0
+got audio_port=23
+
+test_sdp_section_start() test [6]:
+body: "some mgcp header data\r\nand header params\n\r\n\rm=audio 23\r\n"
+got rc=0
+got audio_port=23
+
+test_sdp_section_start() test [7]:
+body: "some mgcp header data\r\nand header params\n\r\nm=audio 23\r\n"
+DLMGCP MGCP response: cannot find start of SDP parameters
+got rc=-22
+
+test_sdp_section_start() test [8]:
+body: "some mgcp header data\r\nand header params\r\n\rm=audio 23\r\n"
+DLMGCP MGCP response: cannot find start of SDP parameters
+got rc=-22
+
+test_sdp_section_start() test [9]:
+body: "some mgcp header data\r\nand header params\n\r\rm=audio 23\r\n"
+DLMGCP MGCP response: cannot find start of SDP parameters
+got rc=-22
Done
diff --git a/tests/mgcp_client/mgcp_client_test.ok b/tests/mgcp_client/mgcp_client_test.ok
index d4efee4..fc6db30 100644
--- a/tests/mgcp_client/mgcp_client_test.ok
+++ b/tests/mgcp_client/mgcp_client_test.ok
@@ -43,7 +43,11 @@ C: 2f
I: 11
M: sendrecv
+v=0
+o=- 2f 23 IN IP4 127.0.0.1
+s=-
c=IN IP4 192.168.100.23
+t=0 0
m=audio 1234 RTP/AVP 255
Generated DLCX message:
@@ -59,4 +63,43 @@ RSIP 5 23@mgw MGCP 1.0
Overfolow test:
+
+test_mgcp_client_cancel():
+composed:
+-----
+CRCX 1 23@mgw MGCP 1.0
+C: 2f
+I: 11
+L: p:20, a:AMR, nt:IN
+M: sendrecv
+
+-----
+composed response:
+-----
+200 1 OK
+I: 1
+
+v=0
+
+-----
+
+test_sdp_section_start() test [0]:
+
+test_sdp_section_start() test [1]:
+
+test_sdp_section_start() test [2]:
+
+test_sdp_section_start() test [3]:
+
+test_sdp_section_start() test [4]:
+
+test_sdp_section_start() test [5]:
+
+test_sdp_section_start() test [6]:
+
+test_sdp_section_start() test [7]:
+
+test_sdp_section_start() test [8]:
+
+test_sdp_section_start() test [9]:
Done