Compare commits

..

1 Commits

Author SHA1 Message Date
Harald Welte
15f64b5199 osmo-mgw: Use libosmocore socket abstraction
There's no need for us to use the sockets API directly:  We have
pretty nice socket helper functions in libosmocore, let's make
use of them.

Change-Id: I39d47b8a27f683060a2facf2dbecff8d00c19ce9
2017-12-14 13:57:16 +01:00
50 changed files with 559 additions and 2001 deletions

View File

@@ -20,6 +20,7 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
libosmo-legacy-mgcp.pc \
libosmo-mgcp-client.pc \
libosmo-mgcp.pc \
$(NULL)
BUILT_SOURCES = $(top_srcdir)/.version

View File

@@ -24,3 +24,6 @@
# If any interfaces have been removed or changed since the last public release, a=0.
#
#library what description / commit summary line
libosmo-mgcp API/ABI change parse and represent connection identifiers as hex strings
libosmo-mgcp API/ABI change connection identifiers are assigned by the server, not CA
libosmo-mgcp-client API/ABI change parse and store connection identifier in response

View File

@@ -39,10 +39,10 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
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)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.1.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
@@ -56,24 +56,6 @@ then
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.])],
[osmo_ac_mgcp_transcoding="$enableval"],[osmo_ac_mgcp_transcoding="no"])
@@ -144,15 +126,13 @@ 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

View File

@@ -37,7 +37,7 @@ set -x
cd "$base"
autoreconf --install --force
./configure $MGCP --enable-vty-tests --enable-external-tests --enable-werror
./configure $MGCP --enable-vty-tests --enable-external-tests
$MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh

125
debian/changelog vendored
View File

@@ -1,128 +1,3 @@
osmo-mgw (1.3.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* contrib: Add osmo-mgw systemd service
* legacy: mgcp_protocol: Don't print osmux stats if it is off
* mgcp_stat: Don't print osmux stats if it is off
[ Neels Hofmeyr ]
* fix segfault: DLCX for unknown endpoint: dont try to log NULL endpoint
* MGCP endpoints: parse as decimal, not hex
* add --enable-sanitize config option
* legacy_mgcp: mgcp_test: sanitize: free msgb_ctx
* mgcp_test: test_packet_error_detection: sanitize: free all conns
* mgcp_test: test_no_cycle: sanitize: free endp
* mgcp_test: sanitize: free msgb_ctx
* mgcp_client: don't configure "bts base"
* Revert "mgcp_client: don't configure "bts base"" until osmo-msc is ready
* mgcp_client: add transaction cleanup
* mgcp_client_test makefile: add update_exp target
* cosmetic: mgcp_network: typo in log
* osmo-mgw: Add talloc context introspection via VTY
* mgcp_client: show failure by MGCP SDP section parsing test
* mgcp_client: cosmetic: clean up SDP params parsing
* mgcp_client: detect SDP section-start parsing errors
* compiler warning: ignore deprecated in mgcp_client_test.c
* configure: add --enable-werror
* jenkins.sh: add --enable-werror to configure flags
* cosmetic: mgcp, legacy_mgcp: drop unused vty.h definitions
* use osmo_init_logging2() with proper talloc ctx
[ Philipp Maier ]
* osmux: fix nullpointer dereference
* cosmetic: guard dead osmux vty code with ifdef
* cosmetic: remove prefix "net" from rtp related vty commands
* doc: update sample config file
* cosmetic: use correct VTY port number constant
* vty: simplify endpoint allocation
* vty: do not change number_endpoints at runtime
* MGCP: Connection Identifiers are hex strings
* libosmo-mgcp: Connection Identifiers are allocated by MGW, not CA
* client: use osmo_strlcpy instead of strncpy
* cosmetic: fix sourcecode formatting
* cosmetic: clearly mark endpoint numbers as hex
* client: use string as connection identifier
* conn: remove assertions
* mgcp_test: fix wrong strcmp() parameters
* mgcp_test: fix nullpointer dereference
* mgcp_test: add returncode check
* mgcp_test: fix possible double free
* mcgp_client: mgcp_msg_gen(): add checks to verify params
* network: use originating RTP packet address for loopback
* client: mgcp_response_parse_params: check rtp port
* mgcp: allow endpoints beginning from zero
* client/common: move constant MGCP_ENDPOINT_MAXLEN
* mgcp: make domain name configurable
* cosmetic: protocol: remove unnecessary nul termination
* client: do not insist on \n\n when parsing MGCP messages
* main: display mgcp ip/port
* client: make callid in MDCX mandatory
* client: add missing mandatory SDP fields
* mgcp: permit wildcarded endpoint assignment (CRCX)
* mgcp: add prefix to virtual trunk
* client: eliminate destructive parameter parsing
* client: eliminate destructive head parsing
* cosmetic: client: add doxygen comments
* protocol: fix problem with line break and OSMUX
* protocol: fix missing carriage return
* client: fix sdp parameter ordering
* protocol: check the packetization in local cx options
* cosmetic: remove spaces from pointer symbol
* client: Do not accept endpoint ids with wildcards in responses
* client: do not accept endpoint ids without @ character in responses
* client: prohibit endpoint ids without @ character
* protocol: on wildcarded CRCX return endpoint number as hex
* msg: fix response code on exhausted endp resources
* cosmetic: move mgcp_release_endp() to mgcp_ep.c
* client: use heap to store mgcp_response
* ep: move endpoint struct and define to mgcp_ep.h
* cosmetic: rename mgcp_release_endp to mgcp_endp_release
* cosmetic: rename mgcp_ep.c/h to mgcp_endp.c/h
* protocol: reject DLCX/CRCX/MDCX on unsupported parameters
* protocol: exit cleanly when local cx options check fails
* cosmetic: Add missing \n on log line
* protocol: check requested connection mode
* protocol: fix tagging of wildcarded requests
* protocol: prohibit wildcarded requests for MDCX and DLCX
* mgcp: fix use-after-free and add callback for endpoint cleanup
* client: add an optional FSM interface
* mgcp_client_fsm: Add FSM event names
* cosmetic: mgcp_client_fsm: rename enums
* cosmetic: rename function .._conn_reset() to .._conn_init()
* mgcp_conn: do not touch u.rtp in mgcp_conn_alloc()
* cosmetic: rename .._codec_reset() to .._codec_init()
* mgcp_conn: add function mgcp_rtp_conn_cleanup()
* stats: use libosmocore rate counter for in/out_stream.err_ts_counter
[ Alexander Couzens ]
* debian/control: correct library dependency of osmo-mgw against libosmo-mgcp1
* debian: include systemd service osmo-mgw.service
* Revert "stats: use libosmocore rate counter for in/out_stream.err_ts_counter"
[ Harald Welte ]
* cosmetic: fix whitespaces; we use tabs for indentation
* Fix possible buffer overflow in mgcp_conn_dump()
* osmo-mgw: Update copyright statement
* osmo-mgw: Config file is osmo-mgw.cfg, and not mgcp.cfg
* osmo-mgw: Fix copyright notice
* strct mgcp_rtp_state: Group + document struct members related to patching
* mgcp_rtp_state: grup 'stats' members into sub-structure
* mgcp_rtp_end: Group statistics members into 'stats' sub-struct
* libosmo-mgcp: Cosmetic spelling fixes in comments
* mgcp_msg: We must parse endpoint numbers as hex, not decimal!
* mgcp_internal.h: document more struct members with comments
* centralize handling of common errors like "endpoint not found"
* Return proper MGCP Error codes, as per spec
* osmo-mgw: Use libosmocore socket abstraction
* osmo-bsc_mgcp: Add LIBOSMONETIF_{CFLAGS,LIBS}
* libosmo-mgcp-client is GPLv2+, not AGPLv3+
* Turn libosmo-mgcp into local, non-installed library
[ Stefan Sperling ]
* enable osmo_fsm vty commands in libosmo-mgcp-client vty
-- Pau Espin Pedrol <pespin@sysmocom.de> Thu, 03 May 2018 17:40:35 +0200
osmo-mgw (1.2.0) unstable; urgency=medium
[ Neels Hofmeyr ]

21
debian/control vendored
View File

@@ -16,10 +16,25 @@ Homepage: https://osmocom.org/projects/osmo-mgw
Package: osmo-mgw
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Depends: libosmo-mgcp1, ${misc:Depends}, ${shlibs:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-mgcp-client3
Package: libosmo-mgcp1
Section: libs
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: libosmo-mgcp: Osmocom's Media Gateway server library
Package: libosmo-mgcp-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp1 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp: Osmocom's Media Gateway server library
Package: libosmo-mgcp-client2
Section: libs
Architecture: any
Multi-Arch: same
@@ -31,7 +46,7 @@ Package: libosmo-mgcp-client-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp-client3 (= ${binary:Version}), ${misc:Depends}
Depends: libosmo-mgcp-client2 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: osmo-bsc-mgcp

19
debian/copyright vendored
View File

@@ -21,25 +21,6 @@ License: AGPL-3.0+
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/>.
Files: src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
Copyright: 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
2009 by Harald Welte <laforge@gnumonks.org>
2009-2011 by Holger Hans Peter Freyther
License: GPL-2.0+
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/>.
Files: src/libosmo-legacy-mgcp/g711common.h
Copyright: 2000 Abramo Bagnara <abramo@alsa-project.org>
License: GPL-2.0+

4
debian/libosmo-mgcp-dev.install vendored Normal file
View File

@@ -0,0 +1,4 @@
usr/include/osmocom/mgcp
usr/lib/*/libosmo-mgcp.so
usr/lib/*/libosmo-mgcp.a
usr/lib/*/pkgconfig/libosmo-mgcp.pc

1
debian/libosmo-mgcp1.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/lib/*/libosmo-mgcp.so.*

View File

@@ -7,7 +7,6 @@ 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 \

View File

@@ -1,8 +1,31 @@
#pragma once
#ifndef OPENBSC_VTY_H
#define OPENBSC_VTY_H
#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

View File

@@ -3,7 +3,7 @@ noinst_HEADERS = \
mgcp_msg.h \
mgcp_conn.h \
mgcp_stat.h \
mgcp_endp.h \
mgcp_ep.h \
mgcp_sdp.h \
debug.h \
$(NULL)

View File

@@ -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 behaviour is controlled via the keepalive_interval member of the
* sent. The beviour is controlled viw 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 timer is scheduled and the
* is scheduled. For all vales greater 0, the a 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)
@@ -212,8 +212,6 @@ struct mgcp_config {
* message.
*/
uint16_t osmux_dummy;
/* domain name of the media gateway */
char domain[255+1];
};
/* config management */
@@ -222,6 +220,7 @@ 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);
/*

View File

@@ -68,18 +68,8 @@ 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

View File

@@ -1,99 +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;
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);

View File

@@ -0,0 +1,50 @@
/* 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;

View File

@@ -27,7 +27,6 @@
#include <osmocom/core/select.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/counter.h>
#define CI_UNUSED 0
@@ -51,37 +50,27 @@ struct mgcp_rtp_stream_state {
};
struct mgcp_rtp_state {
/* has this state structure been initialized? */
int initialized;
int patch_ssrc;
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;
uint32_t orig_ssrc;
/* duration of a packet (FIXME: in which unit?) */
int seq_offset;
int32_t timestamp_offset;
uint32_t packet_duration;
struct mgcp_rtp_stream_state in_stream;
struct mgcp_rtp_stream_state out_stream;
/* jitter and packet loss calculation */
struct {
int initialized;
uint16_t base_seq;
uint16_t max_seq;
uint32_t ssrc;
uint32_t jitter;
int32_t transit;
int cycles;
} stats;
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;
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
};
@@ -96,18 +85,13 @@ struct mgcp_rtp_codec {
char *subtype_name;
};
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
/* statistics */
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 */
unsigned int packets_rx;
unsigned int octets_rx;
unsigned int packets_tx;
unsigned int octets_tx;
unsigned int dropped_packets;
struct in_addr addr;
/* in network byte order */
@@ -121,30 +105,23 @@ 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;
};
@@ -180,7 +157,7 @@ struct mgcp_conn_rtp {
/* Sequence bits */
struct mgcp_rtp_state state;
/* taps for the rtp connection; one per direction */
/* taps for the rtp connection */
struct mgcp_rtp_tap tap_in;
struct mgcp_rtp_tap tap_out;
@@ -227,7 +204,7 @@ struct mgcp_conn {
/*!< copy of the mode to restore the original setting (VTY) */
enum mgcp_connection_mode mode_orig;
/*!< connection id to identify the connection */
/*!< connection id to identify the conntion */
char id[MGCP_CONN_ID_LENGTH];
/*!< human readable name (vty, logging) */
@@ -246,9 +223,25 @@ 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
@@ -258,6 +251,7 @@ 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,
@@ -266,7 +260,6 @@ 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);

View File

@@ -1,8 +1,31 @@
#pragma once
#ifndef OPENBSC_VTY_H
#define OPENBSC_VTY_H
#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

View File

@@ -29,9 +29,8 @@ typedef unsigned int mgcp_trans_id_t;
struct mgcp_response_head {
int response_code;
mgcp_trans_id_t trans_id;
char comment[MGCP_COMMENT_MAXLEN];
const char *comment;
char conn_id[MGCP_CONN_ID_LENGTH];
char endpoint[MGCP_ENDPOINT_MAXLEN];
};
struct mgcp_response {
@@ -56,6 +55,9 @@ 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 */

View File

@@ -1,33 +0,0 @@
#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);

10
libosmo-mgcp.pc.in Normal file
View File

@@ -0,0 +1,10 @@
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}/

View File

@@ -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:1:0
LEGACY_MGCP_LIBVERSION=0:0:0
lib_LTLIBRARIES = \
libosmo-legacy-mgcp.la \

View File

@@ -1588,26 +1588,24 @@ void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
msg += nchars;
size -= nchars;
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;
/* 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;
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->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';

View File

@@ -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=3:0:0
MGCP_CLIENT_LIBVERSION=2:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
@@ -29,7 +29,6 @@ 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)

View File

@@ -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 General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* 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 General Public License for more details.
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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/>.
*
*/
@@ -36,8 +36,6 @@
#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 */
@@ -64,9 +62,7 @@ static bool endpoint_in_use(uint16_t id, struct mgcp_client *client)
return false;
}
/*! Pick next free endpoint ID.
* \param[in,out] client MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
/* Find and seize an unsused endpoint id */
int mgcp_client_next_endpoint(struct mgcp_client *client)
{
int i;
@@ -99,9 +95,6 @@ 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)
{
@@ -146,12 +139,15 @@ static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
&comment_pos) != 2)
goto response_parse_failure;
osmo_strlcpy(r->head.comment, r->body + comment_pos, sizeof(r->head.comment));
r->head.comment = r->body + comment_pos;
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:
@@ -185,9 +181,6 @@ static int mgcp_parse_audio_port(struct mgcp_response *r, const char *line)
&r->audio_port) != 1)
goto response_parse_failure;
if (r->audio_port == 0)
goto response_parse_failure;
return 0;
response_parse_failure:
@@ -223,56 +216,26 @@ 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);
data = talloc_strdup(r, r->body);
OSMO_ASSERT(data);
char *data = strstr(r->body, "\n\n");
/* Find beginning of the parameter (SDP) section */
data_ptr = mgcp_find_section_end(data);
if (!data_ptr) {
if (!data) {
LOGP(DLMGCP, LOGL_ERROR,
"MGCP response: cannot find start of SDP parameters\n");
rc = -EINVAL;
goto exit;
"MGCP response: cannot find start of parameters\n");
return -EINVAL;
}
/* 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. */
/* Advance to after the \n\n, replace the second \n with \0. That's
* where the parameters start. */
data ++;
*data = '\0';
data ++;
for_each_non_empty_line(line, data_ptr) {
for_each_non_empty_line(line, data) {
if (!mgcp_line_is_valid(line))
return -EINVAL;
@@ -280,48 +243,36 @@ int mgcp_response_parse_params(struct mgcp_response *r)
case 'm':
rc = mgcp_parse_audio_port(r, line);
if (rc)
goto exit;
return rc;
break;
case 'c':
rc = mgcp_parse_audio_ip(r, line);
if (rc)
goto exit;
return rc;
break;
default:
/* skip unhandled parameters */
break;
}
}
rc = 0;
exit:
talloc_free(data);
return rc;
return 0;
}
/* Parse a line like "X: something" */
static int mgcp_parse_head_param(char *result, unsigned int result_len,
char label, const char *line)
/* Parse a line like "I: 0cedfd5a19542d197af9afe5231f1d61" */
static int mgcp_parse_conn_id(struct mgcp_response *r, 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)
if (memcmp("I: ", 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);
osmo_strlcpy(r->head.conn_id, line + 3, sizeof(r->head.conn_id));
return 0;
response_parse_failure:
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse MGCP response (parameter label: %c)\n", label);
"Failed to parse MGCP response (connectionIdentifier)\n");
return -EINVAL;
}
@@ -331,51 +282,18 @@ 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;
char *data = r->body;
char *data_end = strstr(r->body, "\n\n");
/* 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);
/* Protect SDP body, for_each_non_empty_line() will
* only parse until it hits \0 mark. */
if (data_end)
*data_end = '\0';
for_each_non_empty_line(line, data_ptr) {
for_each_non_empty_line(line, data) {
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);
rc = mgcp_parse_conn_id(r, line);
if (rc)
goto exit;
break;
@@ -385,7 +303,10 @@ static int parse_head_params(struct mgcp_response *r)
}
}
exit:
talloc_free(data);
/* Restore original state */
if (data_end)
*data_end = '\n';
return rc;
}
@@ -411,42 +332,32 @@ 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;
struct mgcp_response r = { 0 };
struct mgcp_response_pending *pending;
int rc;
r = talloc_zero(mgcp, struct mgcp_response);
OSMO_ASSERT(r);
rc = mgcp_response_parse_head(r, msg);
rc = mgcp_response_parse_head(&r, msg);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
rc = 1;
goto error;
return -1;
}
rc = parse_head_params(r);
rc = parse_head_params(&r);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
rc = 1;
goto error;
return -1;
}
pending = mgcp_client_response_pending_get(mgcp, r->head.trans_id);
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);
rc = -ENOENT;
goto error;
r.head.trans_id);
return -ENOENT;
}
mgcp_client_handle_response(mgcp, pending, r);
rc = 0;
error:
talloc_free(r);
return rc;
mgcp_client_handle_response(mgcp, pending, &r);
return 0;
}
static int mgcp_do_read(struct osmo_fd *fd)
@@ -533,9 +444,6 @@ 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)
{
struct sockaddr_in addr;
@@ -581,25 +489,17 @@ 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;
}
/*! 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) */
/* Return the MGCP GW binary IPv4 address in network byte order. */
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
{
return mgcp->remote_addr;
@@ -672,32 +572,29 @@ 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.
*
/* Cancel a pending transaction.
* 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(). */
* 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. */
/* INFO is sufficient, 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.
/* 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.
*/
}
@@ -807,23 +704,17 @@ struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
MGCP_MSG_PRESENCE_CALL_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;
@@ -873,14 +764,6 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
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);
}
@@ -912,32 +795,9 @@ 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 SDP body */
/* Add RTP address and port (SDP) */
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");
@@ -950,11 +810,8 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, "\r\n");
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);
@@ -970,17 +827,12 @@ 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. */
/* Retrieve the MGCP transaction ID from a msgb generated by mgcp_msg_gen() */
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;

View File

@@ -1,669 +0,0 @@
/* (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);
}

View File

@@ -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 General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* 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 General Public License for more details.
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* 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/>.
*
*/
@@ -25,7 +25,6 @@
#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>
@@ -204,6 +203,4 @@ 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();
}

View File

@@ -21,15 +21,19 @@ AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
$(NULL)
noinst_LIBRARIES = \
libosmo-mgcp.a \
# 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 \
$(NULL)
noinst_HEADERS = \
g711common.h \
$(NULL)
libosmo_mgcp_a_SOURCES = \
libosmo_mgcp_la_SOURCES = \
mgcp_protocol.c \
mgcp_network.c \
mgcp_vty.c \
@@ -38,5 +42,7 @@ libosmo_mgcp_a_SOURCES = \
mgcp_msg.c \
mgcp_conn.c \
mgcp_stat.c \
mgcp_endp.c \
mgcp_ep.c \
$(NULL)
libosmo_mgcp_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_LIBVERSION)

View File

@@ -24,7 +24,7 @@
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/gsm/gsm_utils.h>
#include <ctype.h>
@@ -68,7 +68,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
}
/* Reset codec state and free memory */
static void mgcp_rtp_codec_init(struct mgcp_rtp_codec *codec)
static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
{
codec->payload_type = -1;
codec->subtype_name = NULL;
@@ -83,20 +83,22 @@ static void mgcp_rtp_codec_init(struct mgcp_rtp_codec *codec)
talloc_free(codec->audio_name);
}
/* Initialize rtp connection struct with default values */
static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
/* Reset states, free memory, set defaults and reset codec state */
static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_end *end = &conn_rtp->end;
struct mgcp_rtp_end *end = &conn->end;
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;
conn->type = MGCP_RTP_DEFAULT;
conn->osmux.allocated_cid = -1;
end->rtp.fd = -1;
end->rtcp.fd = -1;
memset(&end->stats, 0, sizeof(end->stats));
end->local_port = 0;
end->packets_rx = 0;
end->octets_rx = 0;
end->packets_tx = 0;
end->octets_tx = 0;
end->dropped_packets = 0;
end->rtp_port = end->rtcp_port = 0;
talloc_free(end->fmtp_extra);
end->fmtp_extra = NULL;
@@ -106,16 +108,8 @@ static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = 0;
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);
mgcp_rtp_codec_reset(&end->codec);
mgcp_rtp_codec_reset(&end->alt_codec);
}
/*! allocate a new connection list entry.
@@ -142,6 +136,7 @@ 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->u.rtp.conn = conn;
osmo_strlcpy(conn->name, name, sizeof(conn->name));
rc = mgcp_alloc_id(endp, conn->id);
if (rc < 0) {
@@ -151,7 +146,7 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
switch (type) {
case MGCP_CONN_TYPE_RTP:
mgcp_rtp_conn_init(&conn->u.rtp, conn);
mgcp_rtp_conn_reset(&conn->u.rtp);
break;
default:
/* NOTE: This should never be called with an
@@ -211,15 +206,11 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *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:
mgcp_rtp_conn_cleanup(&conn->u.rtp);
osmux_disable_conn(&conn->u.rtp);
osmux_release_cid(&conn->u.rtp);
mgcp_free_rtp_port(&conn->u.rtp.end);
break;
default:
/* NOTE: This should never be called with an
@@ -263,9 +254,9 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp)
return;
}
/*! dump basic connection information to human readable string.
/*! dump basic connection information to human readble string.
* \param[in] conn to dump
* \returns human readable string */
* \returns human readble string */
char *mgcp_conn_dump(struct mgcp_conn *conn)
{
static char str[sizeof(conn->name)+sizeof(conn->id)+256];

View File

@@ -21,36 +21,12 @@
*
*/
#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.cleanup_cb = mgcp_cleanup_rtp_bridge_cb
.rtp.dispatch_rtp_cb = mgcp_dispatch_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;
}

View File

@@ -28,7 +28,6 @@
#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
@@ -143,7 +142,6 @@ 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) {
@@ -180,112 +178,25 @@ static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
return NULL;
}
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;
return &tcfg->endpoints[endp];
}
/* 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,
int *cause)
const char *mgcp)
{
char *endptr = NULL;
unsigned int gw = INT_MAX;
const char *endpoint_number_str;
struct mgcp_endpoint *endp;
*cause = 0;
if (strncmp(mgcp, "ds/e1", 5) == 0)
return find_e1_endpoint(cfg, mgcp);
/* 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;
}
/* 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 < cfg->trunk.number_endpoints && endptr[0] == '@') {
endp = &cfg->trunk.endpoints[gw];
endp->wildcarded_req = false;
return endp;
}
gw = strtoul(mgcp, &endptr, 10);
if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
return &cfg->trunk.endpoints[gw];
LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
*cause = -500;
return NULL;
}
@@ -298,7 +209,6 @@ 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.
@@ -316,25 +226,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, &cause);
pdata->endp = find_endpoint(pdata->cfg, elem);
if (!pdata->endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Unable to find Endpoint `%s'\n", elem);
return cause;
return -1;
}
break;
case 2:
if (strcmp("MGCP", elem)) {
LOGP(DLMGCP, LOGL_ERROR,
"MGCP header parsing error\n");
return -510;
return -1;
}
break;
case 3:
if (strcmp("1.0", elem)) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
"not supported\n", elem);
return -528;
return -1;
}
break;
}
@@ -345,7 +255,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 -510;
return -1;
}
return 0;

View File

@@ -39,7 +39,7 @@
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/mgcp/debug.h>
#define RTP_SEQ_MOD (1 << 16)
@@ -230,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->patch.timestamp_offset, state->patch.seq_offset,
state->timestamp_offset, state->seq_offset,
ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -324,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->patch.timestamp_offset != timestamp_offset) {
state->patch.timestamp_offset = timestamp_offset;
if (state->timestamp_offset != timestamp_offset) {
state->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->patch.timestamp_offset,
delta_seq, state->timestamp_offset,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -353,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->patch.timestamp_offset);
timestamp + state->timestamp_offset);
/* If there is an alignment error, we have to compensate it */
if (ts_error) {
state->patch.timestamp_offset += ptime - ts_error;
state->timestamp_offset += ptime - ts_error;
LOGP(DRTP, LOGL_NOTICE,
"Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
@@ -365,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->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
state->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 alignment
* error computation function */
* here would point to a serous problem with the alingnment
* error computation fuction */
ts_check = ts_alignment_error(&state->out_stream, ptime,
timestamp + state->patch.timestamp_offset);
timestamp + state->timestamp_offset);
OSMO_ASSERT(ts_check == 0);
/* Return alignment error before compensation */
@@ -386,7 +386,7 @@ 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] maximum size of caller provided voice data buffer
* \param[in] maxmimum 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,
@@ -433,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;
@@ -451,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",
@@ -466,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
@@ -507,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->patch.orig_ssrc = ssrc;
state->in_stream.ssrc = state->orig_ssrc = ssrc;
state->in_stream.last_tsdelta = 0;
state->packet_duration =
mgcp_rtp_packet_duration(endp, rtp_end);
@@ -518,7 +518,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
"endpoint:0x%x initializing stream, SSRC: %u timestamp: %u "
"pkt-duration: %d, from %s:%d\n",
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
state->patch.seq_offset, state->packet_duration,
state->seq_offset, state->packet_duration,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
if (state->packet_duration == 0) {
state->packet_duration =
@@ -542,7 +542,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
int16_t delta_seq;
/* Always increment seqno by 1 */
state->patch.seq_offset =
state->seq_offset =
(state->out_stream.last_seq + 1) - seq;
/* Estimate number of packets that would have been sent */
@@ -554,8 +554,8 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
delta_seq, timestamp);
state->patch.patch_ssrc = 1;
ssrc = state->patch.orig_ssrc;
state->patch_ssrc = 1;
ssrc = state->orig_ssrc;
if (rtp_end->force_constant_ssrc != -1)
rtp_end->force_constant_ssrc -= 1;
@@ -564,7 +564,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
"SeqNo offset: %d, TS offset: %d "
"from %s:%d\n",
ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
state->patch.seq_offset, state->patch.timestamp_offset,
state->seq_offset, state->timestamp_offset,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
}
@@ -575,8 +575,8 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
addr, seq, timestamp, "input",
&state->in_stream.last_tsdelta);
if (state->patch.patch_ssrc)
ssrc = state->patch.orig_ssrc;
if (state->patch_ssrc)
ssrc = state->orig_ssrc;
}
/* Save before patching */
@@ -591,15 +591,15 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp,
timestamp);
/* Store the updated SSRC back to the packet */
if (state->patch.patch_ssrc)
if (state->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->patch.seq_offset;
seq += state->seq_offset;
rtp_hdr->sequence = htons(seq);
timestamp += state->patch.timestamp_offset;
timestamp += state->timestamp_offset;
rtp_hdr->timestamp = htonl(timestamp);
/* Check again, whether the timestamps are still valid */
@@ -692,7 +692,7 @@ 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->stats.dropped_packets += 1;
rtp_end->dropped_packets += 1;
LOGP(DRTP, LOGL_DEBUG,
"endpoint:0x%x output disabled, drop to %s %s "
"rtp_port:%u rtcp_port:%u\n",
@@ -747,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.stats.packets_tx += 1;
conn_dst->end.stats.octets_tx += len;
conn_dst->end.packets_tx += 1;
conn_dst->end.octets_tx += len;
nbytes += len;
buflen = cont;
@@ -767,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.stats.packets_tx += 1;
conn_dst->end.stats.octets_tx += len;
conn_dst->end.packets_tx += 1;
conn_dst->end.octets_tx += len;
return len;
}
@@ -905,7 +905,7 @@ static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
*proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x ", ENDPOINT_NUMBER(endp));
LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
LOGPC(DRTP, LOGL_DEBUG, "receiveing from %s %s %d\n",
conn->conn->name, inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n", ENDPOINT_NUMBER(endp),
@@ -928,8 +928,8 @@ static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
}
/* Increment RX statistics */
conn->end.stats.packets_rx += 1;
conn->end.stats.octets_rx += rc;
conn->end.packets_rx += 1;
conn->end.octets_rx += rc;
/* Forward a copy of the RTP data to a debug ip/port */
forward_data(fd->fd, &conn->tap_in, buf, rc);
@@ -1043,25 +1043,6 @@ 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)
{

View File

@@ -24,7 +24,6 @@
#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;
@@ -143,7 +142,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
* found, the function will automatically allocate one */
* foud a 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)
{
@@ -256,8 +255,8 @@ static void scheduled_tx_net_cb(struct msgb *msg, void *data)
.sin_port = conn_net->end.rtp_port,
};
conn_bts->end.stats.octets_tx += msg->len;
conn_bts->end.stats.packets_tx++;
conn_bts->end.octets_tx += msg->len;
conn_bts->end.packets_tx++;
/* Send RTP data to NET */
/* FIXME: Get rid of conn_bts and conn_net! */
@@ -283,8 +282,8 @@ static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
.sin_port = conn_bts->end.rtp_port,
};
conn_net->end.stats.octets_tx += msg->len;
conn_net->end.stats.packets_tx++;
conn_net->end.octets_tx += msg->len;
conn_net->end.packets_tx++;
/* Send RTP data to BTS */
/* FIXME: Get rid of conn_bts and conn_net! */

View File

@@ -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_endp.h>
#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/mgcp/mgcp_sdp.h>
struct mgcp_request {
@@ -192,41 +192,17 @@ 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,
bool add_conn_params)
const char *trans_id)
{
const char *addr = endp->cfg->local_ip;
struct msgb *sdp;
int rc;
struct msgb *result;
char osmux_extension[strlen("X-Osmux: 255") + 1];
char osmux_extension[strlen("\nX-Osmux: 255") + 1];
char local_ip_addr[INET_ADDRSTRLEN];
sdp = msgb_alloc_headroom(4096, 128, "sdp record");
@@ -239,28 +215,15 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
}
if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
sprintf(osmux_extension, "X-Osmux: %u", conn->osmux.cid);
sprintf(osmux_extension, "\nX-Osmux: %u", conn->osmux.cid);
conn->osmux.state = OSMUX_STATE_ACTIVATING;
} else {
osmux_extension[0] = '\0';
}
/* 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 = msgb_printf(sdp, "I: %s%s\n\n", conn->conn->id, osmux_extension);
if (rc < 0)
goto error;
rc = mgcp_write_response_sdp(endp, conn, sdp, addr);
if (rc < 0)
@@ -289,7 +252,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 rc, i, code, handled = 0;
int i, code, handled = 0;
struct msgb *resp = NULL;
char *data;
@@ -317,19 +280,13 @@ 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);
rc = mgcp_parse_header(&pdata, data);
pdata.found = 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],
@@ -351,13 +308,19 @@ 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");
return create_ok_response(p->endp, 200, "AUEP", p->trans);
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);
}
/* Try to find a free port by attempting to bind on it. Also handle the
/* Try to find a free port by attemting 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 attempt,
* nevertheless, try at least the next 200 ports before giving up */
* to the next free port, binding should work on the first attemt,
* neverless, 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;
@@ -393,10 +356,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 exactly
* The string is stored in the 'string' field. A NULL string is handled excatlyy
* like an empty string, the 'string' field is never NULL after this function
* has been called. */
static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
static void set_local_cx_options(void *ctx, struct mgcp_lco *lco,
const char *options)
{
char *p_opt, *a_opt;
@@ -420,15 +383,6 @@ static int 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,
@@ -495,10 +449,12 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
struct mgcp_conn_rtp *conn = NULL;
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))
@@ -535,7 +491,6 @@ 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;
}
}
@@ -548,14 +503,14 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x insufficient parameters, missing callid\n",
ENDPOINT_NUMBER(endp));
return create_err_response(endp, 516, "CRCX", p->trans);
return create_err_response(endp, 400, "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, 517, "CRCX", p->trans);
return create_err_response(endp, 400, "CRCX", p->trans);
}
/* Check if we are able to accept the creation of another connection */
@@ -571,7 +526,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, 540, "CRCX", p->trans);
return create_err_response(endp, 400, "CRCX", p->trans);
}
}
@@ -584,7 +539,7 @@ mgcp_header_done:
if (tcfg->force_realloc)
/* This is not our call, toss everything by releasing
* the entire endpoint. (rude!) */
mgcp_endp_release(endp);
mgcp_release_endp(endp);
else {
/* This is not our call, leave everything as it is and
* return with an error. */
@@ -593,20 +548,13 @@ mgcp_header_done:
}
/* Set the callid, creation of another connection will only be possible
* when the callid matches up. (Connections are distinguished by their
* when the callid matches up. (Connections are distinuished by their
* connection ids) */
endp->callid = talloc_strdup(tcfg->endpoints, callid);
/* Extract audio codec information */
rc = set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x inavlid local connection options!\n",
ENDPOINT_NUMBER(endp));
error_code = rc;
goto error2;
}
set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
snprintf(conn_name, sizeof(conn_name), "%s", callid);
_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
@@ -654,17 +602,6 @@ mgcp_header_done:
mgcp_rtp_end_config(endp, 0, &conn->end);
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& 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;
}
@@ -686,7 +623,7 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_NOTICE,
"CRCX: endpoint:0x%x CRCX rejected by policy\n",
ENDPOINT_NUMBER(endp));
mgcp_endp_release(endp);
mgcp_release_endp(endp);
return create_err_response(endp, 400, "CRCX", p->trans);
break;
case MGCP_POLICY_DEFER:
@@ -714,9 +651,9 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_NOTICE,
"CRCX: endpoint:0x%x connection successfully created\n",
ENDPOINT_NUMBER(endp));
return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
return create_response_with_sdp(endp, conn, "CRCX", p->trans);
error2:
mgcp_endp_release(endp);
mgcp_release_endp(endp);
LOGP(DLMGCP, LOGL_NOTICE,
"CRCX: endpoint:0x%x unable to create connection resource error\n",
ENDPOINT_NUMBER(endp));
@@ -735,17 +672,11 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
const char *mode = NULL;
struct mgcp_conn_rtp *conn = NULL;
const char *conn_id = NULL;
int rc;
LOGP(DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
/* 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 (p->found != 0)
return create_err_response(NULL, 510, "MDCX", p->trans);
if (llist_count(&endp->conns) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -760,17 +691,13 @@ 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) {
error_code = 516;
if (mgcp_verify_call_id(endp, line + 3) != 0)
goto error3;
}
break;
case 'I':
conn_id = (const char *)line + 3;
if (mgcp_verify_ci(endp, conn_id) != 0) {
error_code = 515;
if (mgcp_verify_ci(endp, conn_id) != 0)
goto error3;
}
break;
case 'L':
local_options = (const char *)line + 3;
@@ -789,7 +716,6 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
LOGP(DLMGCP, LOGL_NOTICE,
"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;
}
}
@@ -799,7 +725,7 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_ERROR,
"MDCX: endpoint:0x%x insufficient parameters, missing ci (connectionIdentifier)\n",
ENDPOINT_NUMBER(endp));
return create_err_response(endp, 515, "MDCX", p->trans);
return create_err_response(endp, 400, "MDCX", p->trans);
}
conn = mgcp_conn_get_rtp(endp, conn_id);
@@ -817,31 +743,13 @@ mgcp_header_done:
if (have_sdp)
mgcp_parse_sdp_data(endp, conn, p);
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;
}
set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
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;
@@ -895,7 +803,7 @@ mgcp_header_done:
LOGP(DLMGCP, LOGL_NOTICE,
"MDCX: endpoint:0x%x connection successfully modified\n",
ENDPOINT_NUMBER(endp));
return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
return create_response_with_sdp(endp, conn, "MDCX", p->trans);
error3:
return create_err_response(endp, error_code, "MDCX", p->trans);
@@ -916,23 +824,18 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
const char *conn_id = NULL;
struct mgcp_conn_rtp *conn = NULL;
if (p->found != 0)
return create_err_response(NULL, error_code, "DLCX", p->trans);
LOGP(DLMGCP, LOGL_NOTICE,
"DLCX: endpoint:0x%x deleting connection ...\n",
ENDPOINT_NUMBER(endp));
/* 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:0x%x endpoint is not holding a connection.\n",
ENDPOINT_NUMBER(endp));
return create_err_response(endp, 515, "DLCX", p->trans);
return create_err_response(endp, 400, "DLCX", p->trans);
}
for_each_line(line, p->save) {
@@ -941,17 +844,13 @@ 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) {
error_code = 516;
if (mgcp_verify_call_id(endp, line + 3) != 0)
goto error3;
}
break;
case 'I':
conn_id = (const char *)line + 3;
if (mgcp_verify_ci(endp, conn_id) != 0) {
error_code = 515;
if (mgcp_verify_ci(endp, conn_id) != 0)
goto error3;
}
break;
case 'Z':
silent = strcmp("noanswer", line + 3) == 0;
@@ -960,7 +859,6 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
LOGP(DLMGCP, LOGL_NOTICE,
"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;
}
}
@@ -997,7 +895,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
"DLCX: endpoint:0x%x missing ci (connectionIdentifier), will remove all connections at once\n",
ENDPOINT_NUMBER(endp));
mgcp_endp_release(endp);
mgcp_release_endp(endp);
/* Note: In this case we do not return any statistics,
* as we assume that the client is not interested in
@@ -1024,7 +922,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
/* 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_endp_release(endp);
mgcp_release_endp(endp);
LOGP(DLMGCP, LOGL_DEBUG,
"DLCX: endpoint:0x%x endpoint released\n",
ENDPOINT_NUMBER(endp));
@@ -1060,6 +958,12 @@ 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;
@@ -1085,6 +989,9 @@ 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':
@@ -1106,7 +1013,7 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
}
/* Connection keepalive timer, will take care that dummy packets are send
* regularly, so that NAT connections stay open */
* regulary, so that NAT connections stay open */
static void mgcp_keepalive_timer_cb(void *_tcfg)
{
struct mgcp_trunk_config *tcfg = _tcfg;
@@ -1175,8 +1082,6 @@ 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;
@@ -1279,6 +1184,28 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
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:0x%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);
@@ -1291,16 +1218,13 @@ 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;
len = snprintf(buf, sizeof(buf),
"RSIP 1 *@%s MGCP 1.0\r\n", cfg->domain);
if (len < 0)
return -1;
static const char mgcp_reset[] = {
"RSIP 1 *@mgw MGCP 1.0\r\n"
};
rc = send_agent(cfg, buf, len);
rc = send_agent(cfg, mgcp_reset, sizeof mgcp_reset - 1);
if (rc <= 0)
return -1;
@@ -1314,15 +1238,17 @@ 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[MGCP_ENDPOINT_MAXLEN + 128];
char buf[128];
int len;
int rc;
len = snprintf(buf, sizeof(buf),
"RSIP 39 %x@%s MGCP 1.0\r\n", endpoint, endp->cfg->domain);
"RSIP 39 %x@mgw MGCP 1.0\r\n", endpoint);
if (len < 0)
return -1;
buf[sizeof(buf) - 1] = '\0';
rc = send_agent(endp->cfg, buf, len);
if (rc <= 0)
return -1;

View File

@@ -24,7 +24,6 @@
#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>

View File

@@ -23,7 +23,6 @@
*/
#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 */
@@ -31,10 +30,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;
@@ -44,8 +43,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->stats.packets_rx;
if (*expected < end->stats.packets_rx) {
*loss = *expected - end->packets_rx;
if (*expected < end->packets_rx) {
if (*loss > 0)
*loss = INT_MIN;
} else {
@@ -57,9 +56,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 */
@@ -75,8 +74,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.stats.packets_tx, conn->end.stats.octets_tx,
conn->end.stats.packets_rx, conn->end.stats.octets_rx,
conn->end.packets_tx, conn->end.octets_tx,
conn->end.packets_rx, conn->end.octets_rx,
ploss, jitter);
if (nchars < 0 || nchars >= str_len)
goto truncate;
@@ -84,23 +83,21 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
str += nchars;
str_len -= nchars;
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;
/* 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;
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->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:

View File

@@ -27,7 +27,6 @@
#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>
@@ -64,7 +63,6 @@ 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);
@@ -169,7 +167,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->stats.dropped_packets, VTY_NEWLINE,
end->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,
@@ -1048,7 +1046,7 @@ DEFUN(free_endp, free_endp_cmd,
}
endp = &trunk->endpoints[endp_no];
mgcp_endp_release(endp);
mgcp_release_endp(endp);
return CMD_SUCCESS;
}
@@ -1181,14 +1179,6 @@ 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);
@@ -1250,7 +1240,6 @@ 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);

View File

@@ -8,7 +8,6 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(LIBBCG729_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -25,7 +24,6 @@ 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)

View File

@@ -244,7 +244,7 @@ int main(int argc, char **argv)
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
osmo_init_ignore_signals();
osmo_init_logging2(tall_bsc_ctx, &log_info);
osmo_init_logging(&log_info);
cfg = mgcp_config_alloc();
if (!cfg)

View File

@@ -8,8 +8,6 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -22,9 +20,7 @@ osmo_mgw_SOURCES = \
$(NULL)
osmo_mgw_LDADD = \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(NULL)

View File

@@ -37,7 +37,6 @@
#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>
@@ -53,7 +52,6 @@
#include <osmocom/vty/ports.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/misc.h>
#include "../../bscconfig.h"
@@ -191,7 +189,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_endp_release(&reset_trunk->endpoints[i]);
mgcp_release_endp(&reset_trunk->endpoints[i]);
}
return 0;
@@ -257,12 +255,10 @@ int main(int argc, char **argv)
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_logging2(tall_bsc_ctx, &log_info);
osmo_init_logging(&log_info);
cfg = mgcp_config_alloc();
if (!cfg)
@@ -271,7 +267,6 @@ int main(int argc, char **argv)
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();
@@ -314,8 +309,7 @@ int main(int argc, char **argv)
return -1;
}
LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP, listen on %s:%u\n",
cfg->source_addr, cfg->source_port);
LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
/* initialisation */
srand(time(NULL));

View File

@@ -268,9 +268,7 @@ 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"
#define DLCX_RET_OSMUX DLCX_RET \
"P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
"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" \
@@ -1214,9 +1212,8 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
void *msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
osmo_init_logging(&log_info);
test_strline();
test_values();

View File

@@ -588,8 +588,7 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
int rc;
void *ctx = talloc_named_const(NULL, 0, "mgcp_transcoding_test");
osmo_init_logging2(ctx, &log_info);
osmo_init_logging(&log_info);
printf("=== Transcoding Good Cases ===\n");

View File

@@ -8,8 +8,6 @@ AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -31,10 +29,9 @@ mgcp_test_SOURCES = \
$(NULL)
mgcp_test_LDADD = \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
-lm \

View File

@@ -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_endp.h>
#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
@@ -66,18 +66,18 @@ static void test_strline(void)
OSMO_ASSERT(counter == EXPECTED_NUMBER_OF_LINES);
}
#define AUEP1 "AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
#define AUEP1 "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n"
#define AUEP1_RET "200 158663169 OK\r\n"
#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
#define AUEP2 "AUEP 18983213 ds/e1-2/1@172.16.6.66 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@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_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_RET "400 18983214 FAIL\r\n"
#define MDCX3 \
@@ -86,7 +86,8 @@ static void test_strline(void)
#define MDCX3_RET \
"200 18983215 OK\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -98,7 +99,8 @@ static void test_strline(void)
#define MDCX3A_RET \
"200 18983215 OK\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -110,7 +112,8 @@ static void test_strline(void)
#define MDCX3_FMTP_RET \
"200 18983215 OK\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -138,7 +141,8 @@ static void test_strline(void)
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -150,7 +154,8 @@ static void test_strline(void)
#define MDCX4_RO_RET(Ident) \
"200 " Ident " OK\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -247,8 +252,8 @@ static void test_strline(void)
#define CRCX_RET \
"200 2 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -260,8 +265,8 @@ static void test_strline(void)
#define CRCX_RET_NO_RTPMAP \
"200 2 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -272,8 +277,8 @@ static void test_strline(void)
#define CRCX_FMTP_RET \
"200 2 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -296,8 +301,8 @@ static void test_strline(void)
#define CRCX_ZYN_RET \
"200 2 OK\r\n" \
"I: %s\r\n" \
"\r\n" \
"I: %s\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"s=-\r\n" \
@@ -314,9 +319,7 @@ static void test_strline(void)
#define DLCX_RET \
"250 7 OK\r\n" \
"P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
#define DLCX_RET_OSMUX DLCX_RET \
"P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
"X-Osmo-CP: EC TI=0, TO=0\r\n"
#define RQNT \
@@ -558,39 +561,25 @@ static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
{
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 (!conn_id_ptr)
return -EINVAL;
memset(conn_id, 0, conn_id_len);
memcpy(conn_id, conn_id_ptr + 3, 32);
for (i = 0; i < conn_id_len; i++) {
if (conn_id[i] == '\n' || conn_id[i] == '\r')
conn_id[i] = '\0';
}
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);
/* 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;
return 0;
}
/* Check response, automatically patch connection ID if needed */
@@ -927,12 +916,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.stats.packets_rx = pl_test_dat[i].packets;
rtp.packets_rx = pl_test_dat[i].packets;
calc_loss(&state, &rtp, &expected, &loss);
if (loss != pl_test_dat[i].loss
@@ -1194,7 +1183,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;
@@ -1326,7 +1315,7 @@ static void test_multilple_codec(void)
/* Free the previous endpoint and the data and
* check if the connection really vanished... */
mgcp_endp_release(endp);
mgcp_release_endp(endp);
talloc_free(endp->last_response);
talloc_free(endp->last_trans);
endp->last_response = endp->last_trans = NULL;
@@ -1373,31 +1362,31 @@ static void test_no_cycle(void)
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);
mgcp_release_endp(endp);
talloc_free(cfg);
}
@@ -1428,7 +1417,7 @@ static void test_no_name(void)
msgb_free(inp);
msgb_free(msg);
mgcp_endp_release(&cfg->trunk.endpoints[1]);
mgcp_release_endp(&cfg->trunk.endpoints[1]);
talloc_free(cfg);
}
@@ -1467,9 +1456,8 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
void *msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
osmo_init_logging(&log_info);
test_strline();
test_values();

View File

@@ -16,7 +16,7 @@ line: ''
Testing AUEP1
creating message from statically defined input:
---------8<---------
AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0
AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0
---------8<---------
checking response:
@@ -28,7 +28,7 @@ Response matches our expectations.
Testing AUEP2
creating message from statically defined input:
---------8<---------
AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0
AUEP 18983213 ds/e1-2/1@172.16.6.66 MGCP 1.0
---------8<---------
checking response:
@@ -40,7 +40,7 @@ Response matches our expectations.
Testing MDCX1
creating message from statically defined input:
---------8<---------
MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0
MDCX 18983213 ds/e1-3/1@172.16.6.66 MGCP 1.0
---------8<---------
checking response:
@@ -52,7 +52,7 @@ Response matches our expectations.
Testing MDCX2
creating message from statically defined input:
---------8<---------
MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0
MDCX 18983214 ds/e1-1/2@172.16.6.66 MGCP 1.0
---------8<---------
checking response:
@@ -569,6 +569,7 @@ creating message from statically defined input:
---------8<---------
creating message from statically defined input:
---------8<---------
DLCX 7 1@mgw MGCP 1.0
I: %s
C: 2

View File

@@ -18,8 +18,6 @@
* 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>
@@ -273,109 +271,6 @@ void test_mgcp_client_cancel()
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[] = {
};
@@ -389,7 +284,7 @@ int main(int argc, char **argv)
{
ctx = talloc_named_const(NULL, 1, "mgcp_client_test");
msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
osmo_init_logging(&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);
@@ -402,7 +297,6 @@ int main(int argc, char **argv)
test_crcx();
test_mgcp_msg();
test_mgcp_client_cancel();
test_sdp_section_start();
printf("Done\n");
fprintf(stderr, "Done\n");

View File

@@ -12,54 +12,4 @@ 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

View File

@@ -43,11 +43,7 @@ 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:
@@ -82,24 +78,4 @@ 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