mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					51565999da | ||
| 
						 | 
					fb8624ed1e | ||
| 
						 | 
					1d23dfb0aa | ||
| 
						 | 
					6087326beb | 
							
								
								
									
										17
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								configure.ac
									
									
									
									
									
								
							@@ -44,16 +44,15 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
 | 
				
			|||||||
AC_SUBST(LIBRARY_DLSYM)
 | 
					AC_SUBST(LIBRARY_DLSYM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.4.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
					CFLAGS="$CFLAGS -pthread"
 | 
				
			||||||
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
					 | 
				
			||||||
LDFLAGS="$LDFLAGS -pthread"
 | 
					LDFLAGS="$LDFLAGS -pthread"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,30 +29,30 @@ BuildRequires:  pkgconfig >= 0.20
 | 
				
			|||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
%endif
 | 
					%endif
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.4.0
 | 
					BuildRequires:  pkgconfig(libosmo-netif) >= 1.3.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.9.0
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.9.0
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.9.0
 | 
					BuildRequires:  pkgconfig(libosmogsm) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.9.0
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.9.0
 | 
					BuildRequires:  pkgconfig(libosmocoding) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmoabis) >= 1.4.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmotrau) >= 1.4.0
 | 
				
			||||||
%{?systemd_requires}
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description
 | 
					%description
 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client12
 | 
					%package -n libosmo-mgcp-client11
 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          System/Libraries
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client12
 | 
					%description -n libosmo-mgcp-client11
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					Osmocom's Media Gateway Control Protocol client library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					%package -n libosmo-mgcp-client-devel
 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					Group:          Development/Libraries/C and C++
 | 
				
			||||||
Requires:       libosmo-mgcp-client12 = %{version}
 | 
					Requires:       libosmo-mgcp-client11 = %{version}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					%description -n libosmo-mgcp-client-devel
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					Osmocom's Media Gateway Control Protocol client librarary.
 | 
				
			||||||
@@ -90,8 +90,8 @@ find %{buildroot} -type f -name "*.la" -delete -print
 | 
				
			|||||||
%check
 | 
					%check
 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%post   -n libosmo-mgcp-client12 -p /sbin/ldconfig
 | 
					%post   -n libosmo-mgcp-client11 -p /sbin/ldconfig
 | 
				
			||||||
%postun -n libosmo-mgcp-client12 -p /sbin/ldconfig
 | 
					%postun -n libosmo-mgcp-client11 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
%preun
 | 
					%preun
 | 
				
			||||||
@@ -119,8 +119,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
%dir %{_sysconfdir}/osmocom
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client12
 | 
					%files -n libosmo-mgcp-client11
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.12*
 | 
					%{_libdir}/libosmo-mgcp-client.so.11*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					%files -n libosmo-mgcp-client-devel
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					%{_libdir}/libosmo-mgcp-client.so
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										80
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,82 +1,14 @@
 | 
				
			|||||||
osmo-mgw (1.12.1) unstable; urgency=medium
 | 
					osmo-mgw (1.11.2) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					 | 
				
			||||||
  * mgcp-client: Fix missing include in mgcp_client_pool.h
 | 
					 | 
				
			||||||
  * mgcp-client: Introduce API osmo_mgcpc_ep_local_name()
 | 
					 | 
				
			||||||
  * mgw: Configure IuUP if codec set during MDCX
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 -- Oliver Smith <osmith@sysmocom.de>  Thu, 28 Sep 2023 15:58:17 +0200
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
osmo-mgw (1.12.0) unstable; urgency=medium
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Philipp Maier ]
 | 
					 | 
				
			||||||
  * mgcp_sdp: add spec reference
 | 
					 | 
				
			||||||
  * mgcp_sdp: cosmetic: remove newline
 | 
					 | 
				
			||||||
  * mgcp_endp: cosmetic move mgcp_endp_release to the end
 | 
					 | 
				
			||||||
  * mgcp_endp: cosmetic: remove unnecessary new line
 | 
					 | 
				
			||||||
  * mgcp_e1: fix log output
 | 
					 | 
				
			||||||
  * mgcp_e1: be more frugal withe E1 line resources
 | 
					 | 
				
			||||||
  * mgcp_client: fix sourcecode formatting
 | 
					 | 
				
			||||||
  * mgcp_e1: fix typo
 | 
					 | 
				
			||||||
  * mgcp_e1: rewrite comment
 | 
					 | 
				
			||||||
  * mgcp_e1: rename e1_send to e1_send_ts_frame
 | 
					 | 
				
			||||||
  * mgcp_e1: cosmetic: rewrite comment
 | 
					 | 
				
			||||||
  * Revert "mgcp_codec: do not differentiate between oa and bwe when comparing codec"
 | 
					 | 
				
			||||||
  * mgcp_codec: fix oa/bwe comparison in mgcp_codec_pt_translate()
 | 
					 | 
				
			||||||
  * mgcp_codec: refactor payload type converstion
 | 
					 | 
				
			||||||
  * mgcp_codec: cosmetic: remove line break in api-doc
 | 
					 | 
				
			||||||
  * mgcp_network: fix apidoc
 | 
					 | 
				
			||||||
  * mgcp_vty: add warnings for deprecated config options
 | 
					 | 
				
			||||||
  * mgcp_codec: move mgcp_codec_decide down
 | 
					 | 
				
			||||||
  * mgcp_codec: fix codec decision
 | 
					 | 
				
			||||||
  * mgcp_network: do not deliver RTP packets with unpatched PT
 | 
					 | 
				
			||||||
  * mgcp_codec: be sensitive about IuFP when checking codecs
 | 
					 | 
				
			||||||
  * mgcp_client.h: also add spec ref to the other 3gpp defined payload types
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Harald Welte ]
 | 
					 | 
				
			||||||
  * cosmetic: Fix grammar suggesting reading _the_ user manual
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ arehbein ]
 | 
					 | 
				
			||||||
  * Transition to use of 'telnet_init_default'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Oliver Smith ]
 | 
					 | 
				
			||||||
  * mgcp_client: mgcp_msg_gen: add more error logs
 | 
					 | 
				
			||||||
  * mgcp_client_pool: add mgcp_client_pool_empty()
 | 
					 | 
				
			||||||
  * Cosmetic: mgcp_client: fix typo
 | 
					 | 
				
			||||||
  * debian: set compat level to 10
 | 
					 | 
				
			||||||
  * systemd: depend on networking-online.target
 | 
					  * systemd: depend on networking-online.target
 | 
				
			||||||
  * Cosmetic: fix a typo
 | 
					 | 
				
			||||||
  * mgcp_client: check rc of map_str_to_codec
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Fri, 26 May 2023 17:49:29 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.11.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * mgcp_network: Unregister osmo_fd before closing fd
 | 
					  * mgcp_network: Unregister osmo_fd before closing fd
 | 
				
			||||||
  * mgcp-client: Call osmo_fd_unregister() before closing and changing bfd->fd
 | 
					 | 
				
			||||||
  * mgcp-client: Drop unused struct mgcp_client field
 | 
					 | 
				
			||||||
  * mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
 | 
					 | 
				
			||||||
  * mgcp-client: Move some static functions further above
 | 
					 | 
				
			||||||
  * mgw: Allow auditing speciall 'null' endpoint
 | 
					 | 
				
			||||||
  * mgcp-client: Add keepalive feature
 | 
					 | 
				
			||||||
  * mgcp_client: pool: Only pick clients with an MGCP link considered to be UP
 | 
					 | 
				
			||||||
  * mgcp-client: Always mark client as UP if keepalive request-interval disabled
 | 
					 | 
				
			||||||
  * mgcp-client: Mark client as UP when keepalive request-interval/timeout is disabled through VTY
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Vadim Yanitskiy ]
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Fri, 10 Mar 2023 14:55:21 +0100
 | 
				
			||||||
  * */Makefile.am: libraries shall not be in AM_LDFLAGS
 | 
					 | 
				
			||||||
  * tests: use -no-install libtool flag to avoid ./lt-* scripts
 | 
					 | 
				
			||||||
  * tests: $(BUILT_SOURCES) is not defined, depend on osmo-mgw
 | 
					 | 
				
			||||||
  * copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Neels Hofmeyr ]
 | 
					 | 
				
			||||||
  * mgcp_find_section_end(): skip spaces at start of SDP
 | 
					 | 
				
			||||||
  * mgcp_client: simpler error handling
 | 
					 | 
				
			||||||
  * mgcp: fix "L: a:" header parsing: heed ";" separator
 | 
					 | 
				
			||||||
  * mgcp_client: tweak extract_codec_name() implementation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Andreas Eversberg ]
 | 
					 | 
				
			||||||
  * ASCI: Add new mode for voice group/broadcast call
 | 
					 | 
				
			||||||
  * ASCI: Support conference briding with 1..n connections
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 12 Sep 2023 14:48:51 +0200
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-mgw (1.11.0) unstable; urgency=medium
 | 
					osmo-mgw (1.11.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@@ -1 +1 @@
 | 
				
			|||||||
10
 | 
					9
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -2,14 +2,14 @@ Source: osmo-mgw
 | 
				
			|||||||
Section: net
 | 
					Section: net
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
					Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
				
			||||||
Build-Depends: debhelper (>= 10),
 | 
					Build-Depends: debhelper (>=9),
 | 
				
			||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.9.0),
 | 
					               libosmocore-dev (>= 1.8.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.4.0),
 | 
					               libosmo-netif-dev (>= 1.3.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.5.0),
 | 
					               libosmo-abis-dev (>= 1.4.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.5.0)
 | 
					               osmo-gsm-manuals-dev (>= 1.4.0)
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
@@ -21,7 +21,7 @@ Multi-Arch: foreign
 | 
				
			|||||||
Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
					Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
				
			||||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libosmo-mgcp-client12
 | 
					Package: libosmo-mgcp-client11
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
@@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
 | 
				
			|||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Depends: libosmo-mgcp-client12 (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: libosmo-mgcp-client11 (= ${binary:Version}), ${misc:Depends}
 | 
				
			||||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
					Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw-doc
 | 
					Package: osmo-mgw-doc
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@ Files:     *
 | 
				
			|||||||
Copyright: 2009-2014 On-Waves
 | 
					Copyright: 2009-2014 On-Waves
 | 
				
			||||||
           2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
 | 
					           2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
           2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
 | 
					           2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
 | 
				
			||||||
           2016-2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					           2016-2017 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
License:   AGPL-3.0+
 | 
					License:   AGPL-3.0+
 | 
				
			||||||
 This program is free software; you can redistribute it and/or modify
 | 
					 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
 | 
					 it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
@@ -22,7 +22,7 @@ License:   AGPL-3.0+
 | 
				
			|||||||
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files:     src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
 | 
					Files:     src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
 | 
				
			||||||
Copyright: 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					Copyright: 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
           Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
					           Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
				
			||||||
           2009 by Harald Welte <laforge@gnumonks.org>
 | 
					           2009 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
           2009-2011 by Holger Hans Peter Freyther
 | 
					           2009-2011 by Holger Hans Peter Freyther
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,9 +92,3 @@ not yet useable.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
NOTE: the VTY command "show mgcp" can be used to get a list of all available
 | 
					NOTE: the VTY command "show mgcp" can be used to get a list of all available
 | 
				
			||||||
endpoints (including identifiers)
 | 
					endpoints (including identifiers)
 | 
				
			||||||
 | 
					 | 
				
			||||||
=== The `null` endpoint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OsmoMGW offers a special `null@<domain>` endpoint which can be audited at all times.
 | 
					 | 
				
			||||||
This is useful for MGCP clients who wish to submit requests to OsmoMGW
 | 
					 | 
				
			||||||
periodically to find out whether it is still reachable and in a working state.
 | 
					 | 
				
			||||||
@@ -3,7 +3,6 @@ SUBDIRS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nobase_include_HEADERS = \
 | 
					nobase_include_HEADERS = \
 | 
				
			||||||
	osmocom/mgcp_client/defs.h \
 | 
					 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client.h \
 | 
						osmocom/mgcp_client/mgcp_client.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,9 +13,9 @@ struct mgcp_conn_rtp;
 | 
				
			|||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
					void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
					void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
					int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
 | 
					int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
					bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,6 @@ enum mgcp_connection_mode {
 | 
				
			|||||||
	MGCP_CONN_SEND_ONLY = 2,
 | 
						MGCP_CONN_SEND_ONLY = 2,
 | 
				
			||||||
	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
 | 
						MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
 | 
				
			||||||
	MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
 | 
						MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
 | 
				
			||||||
	MGCP_CONN_CONFECHO  = 8 | MGCP_CONN_RECV_SEND,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
					#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,5 +23,5 @@ static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
 | 
					int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
 | 
				
			||||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts);
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
 | 
					int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,10 +130,10 @@ struct mgcp_endpoint {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
 | 
					struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
 | 
				
			||||||
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
					int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
bool mgcp_endp_is_wildcarded(const char *epname);
 | 
					bool mgcp_endp_is_wildcarded(const char *epname);
 | 
				
			||||||
bool mgcp_endp_is_null(const char *epname);
 | 
					 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			||||||
					      const struct mgcp_trunk *trunk);
 | 
										      const struct mgcp_trunk *trunk);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			||||||
@@ -145,4 +145,3 @@ void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
 | 
				
			|||||||
			 const struct mgcp_trunk *trunk);
 | 
								 const struct mgcp_trunk *trunk);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
				
			||||||
			const struct mgcp_trunk *trunk);
 | 
								const struct mgcp_trunk *trunk);
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ struct mgcp_trunk {
 | 
				
			|||||||
	int audio_send_ptime;
 | 
						int audio_send_ptime;
 | 
				
			||||||
	int audio_send_name;
 | 
						int audio_send_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int no_audio_transcoding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int omit_rtcp;
 | 
						int omit_rtcp;
 | 
				
			||||||
	int keepalive_interval;
 | 
						int keepalive_interval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,7 +66,7 @@ struct mgcp_trunk {
 | 
				
			|||||||
		/* E1 specific */
 | 
							/* E1 specific */
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			unsigned int vty_line_nr;
 | 
								unsigned int vty_line_nr;
 | 
				
			||||||
			uint8_t ts_usecount[NUM_E1_TS-1];
 | 
								bool ts_in_use[NUM_E1_TS-1];
 | 
				
			||||||
			struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
 | 
								struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
 | 
				
			||||||
			/* Note: on an E1 line TS 0 is devoted to framing and
 | 
								/* Note: on an E1 line TS 0 is devoted to framing and
 | 
				
			||||||
			 * alignment and therefore only NUM_E1_TS-1 timeslots
 | 
								 * alignment and therefore only NUM_E1_TS-1 timeslots
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
#include <osmocom/core/defs.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if BUILDING_LIBOSMOMGCPCLIENT
 | 
					 | 
				
			||||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text) OSMO_DEPRECATED(text)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@@ -3,7 +3,6 @@
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/defs.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_common.h>
 | 
					#include <osmocom/mgcp_client/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
					/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
				
			||||||
@@ -11,7 +10,7 @@
 | 
				
			|||||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
 | 
					#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
					#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
					#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
				
			||||||
#define MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP "null"
 | 
					
 | 
				
			||||||
#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
 | 
					#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb;
 | 
					struct msgb;
 | 
				
			||||||
@@ -36,12 +35,6 @@ struct mgcp_client_conf {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* human readable name / description */
 | 
						/* human readable name / description */
 | 
				
			||||||
	char *description;
 | 
						char *description;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		uint32_t timeout_sec;
 | 
					 | 
				
			||||||
		uint32_t req_interval_sec;
 | 
					 | 
				
			||||||
		char req_endpoint_name[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	} keepalive;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef unsigned int mgcp_trans_id_t;
 | 
					typedef unsigned int mgcp_trans_id_t;
 | 
				
			||||||
@@ -52,10 +45,10 @@ enum mgcp_codecs {
 | 
				
			|||||||
	CODEC_GSM_8000_1 = 3,
 | 
						CODEC_GSM_8000_1 = 3,
 | 
				
			||||||
	CODEC_PCMA_8000_1 = 8,
 | 
						CODEC_PCMA_8000_1 = 8,
 | 
				
			||||||
	CODEC_G729_8000_1 = 18,
 | 
						CODEC_G729_8000_1 = 18,
 | 
				
			||||||
	CODEC_GSMEFR_8000_1 = 110,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
						CODEC_GSMEFR_8000_1 = 110,
 | 
				
			||||||
	CODEC_GSMHR_8000_1 = 111,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
						CODEC_GSMHR_8000_1 = 111,
 | 
				
			||||||
	CODEC_AMR_8000_1 = 112,		/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
						CODEC_AMR_8000_1 = 112,
 | 
				
			||||||
	CODEC_AMRWB_16000_1 = 113,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
						CODEC_AMRWB_16000_1 = 113,
 | 
				
			||||||
	CODEC_IUFP = 96,
 | 
						CODEC_IUFP = 96,
 | 
				
			||||||
	CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
						CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -140,8 +133,7 @@ struct mgcp_msg {
 | 
				
			|||||||
	struct mgcp_codec_param param;
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
 | 
					void mgcp_client_conf_init(struct mgcp_client_conf *conf);
 | 
				
			||||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf) OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use mgcp_client_conf_alloc() (or even better, switch to the mgcp_client_pool API!)");
 | 
					 | 
				
			||||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
 | 
					void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent);
 | 
					int mgcp_client_config_write(struct vty *vty, const char *indent);
 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
					struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@ static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			|||||||
void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
					void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
					const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep);
 | 
					 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
 | 
					struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/write_queue.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_CB_MGCP_TRANS_ID 0
 | 
					#define MSGB_CB_MGCP_TRANS_ID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,10 +15,13 @@ struct mgcp_client {
 | 
				
			|||||||
	struct osmo_wqueue wq;
 | 
						struct osmo_wqueue wq;
 | 
				
			||||||
	mgcp_trans_id_t next_trans_id;
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
 | 
						struct llist_head inuse_endpoints;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	struct osmo_timer_list keepalive_tx_timer;
 | 
					};
 | 
				
			||||||
	struct osmo_timer_list keepalive_rx_timer;
 | 
					
 | 
				
			||||||
	bool conn_up;
 | 
					struct mgcp_inuse_endpoint {
 | 
				
			||||||
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
						uint16_t id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending {
 | 
					struct mgcp_response_pending {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/vty.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client;
 | 
					struct mgcp_client;
 | 
				
			||||||
struct mgcp_client_pool;
 | 
					struct mgcp_client_pool;
 | 
				
			||||||
struct mgcp_client_pool_member;
 | 
					struct mgcp_client_pool_member;
 | 
				
			||||||
@@ -14,7 +12,6 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
 | 
					int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
 | 
				
			||||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
					unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
				
			||||||
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,12 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(COVERAGE_CFLAGS) \
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Libraries
 | 
					# Libraries
 | 
				
			||||||
SUBDIRS = \
 | 
					SUBDIRS = \
 | 
				
			||||||
	libosmo-mgcp-client \
 | 
						libosmo-mgcp-client \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,12 +14,14 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This is not at all related to the release version, but a range of supported
 | 
					# 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!
 | 
					# API versions. Read TODO_RELEASE in the source tree's root!
 | 
				
			||||||
MGCP_CLIENT_LIBVERSION=13:0:1
 | 
					MGCP_CLIENT_LIBVERSION=11:0:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -38,8 +40,3 @@ libosmo_mgcp_client_la_LDFLAGS = \
 | 
				
			|||||||
	-version-info $(MGCP_CLIENT_LIBVERSION) \
 | 
						-version-info $(MGCP_CLIENT_LIBVERSION) \
 | 
				
			||||||
	-no-undefined \
 | 
						-no-undefined \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					 | 
				
			||||||
libosmo_mgcp_client_la_LIBADD = \
 | 
					 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOVTY_LIBS) \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,16 +69,17 @@ const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			|||||||
static char *extract_codec_name(const char *str)
 | 
					static char *extract_codec_name(const char *str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char buf[64];
 | 
						static char buf[64];
 | 
				
			||||||
	char *pos;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!str)
 | 
						if (!str)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_strlcpy(buf, str, sizeof(buf));
 | 
						osmo_strlcpy(buf, str, sizeof(buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pos = strchr(buf, '/');
 | 
						for (i = 0; i < strlen(buf); i++) {
 | 
				
			||||||
	if (pos)
 | 
							if (buf[i] == '/')
 | 
				
			||||||
		*pos = '\0';
 | 
								buf[i] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return buf;
 | 
						return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -147,7 +148,7 @@ unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			|||||||
	 *  is also ignored and a 1:1 mapping is performed instead. */
 | 
						 *  is also ignored and a 1:1 mapping is performed instead. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we may return the codec directly since enum mgcp_codecs directly
 | 
						/* we may return the codec directly since enum mgcp_codecs directly
 | 
				
			||||||
	 * corresponds to the statically assigned payload types */
 | 
						 * corresponds to the statićally assigned payload types */
 | 
				
			||||||
	if (codec < 96 || codec > 127)
 | 
						if (codec < 96 || codec > 127)
 | 
				
			||||||
		return codec;
 | 
							return codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,7 +194,9 @@ enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			|||||||
	return pt;
 | 
						return pt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void _mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
					/*! Initialize 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 */
 | 
						/* NULL and -1 default to MGCP_CLIENT_*_DEFAULT values */
 | 
				
			||||||
	*conf = (struct mgcp_client_conf){
 | 
						*conf = (struct mgcp_client_conf){
 | 
				
			||||||
@@ -201,39 +204,11 @@ static void _mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
				
			|||||||
		.local_port = -1,
 | 
							.local_port = -1,
 | 
				
			||||||
		.remote_addr = NULL,
 | 
							.remote_addr = NULL,
 | 
				
			||||||
		.remote_port = -1,
 | 
							.remote_port = -1,
 | 
				
			||||||
		.keepalive = {
 | 
					 | 
				
			||||||
			.timeout_sec = 0, /* disabled */
 | 
					 | 
				
			||||||
			.req_interval_sec = 0, /* disabled */
 | 
					 | 
				
			||||||
			.req_endpoint_name = MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&conf->reset_epnames);
 | 
						INIT_LLIST_HEAD(&conf->reset_epnames);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Allocate and initialize MGCP client configuration struct with default values.
 | 
					 | 
				
			||||||
 *  \param[in] ctx talloc context to use as a parent during allocation.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The returned struct can be freed using talloc_free().
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_conf *conf = talloc(ctx, struct mgcp_client_conf);
 | 
					 | 
				
			||||||
	_mgcp_client_conf_init(conf);
 | 
					 | 
				
			||||||
	return conf;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Initialize MGCP client configuration struct with default values.
 | 
					 | 
				
			||||||
 *  \param[out] conf Client configuration.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This function is deprecated and should not be used, as it may break if size
 | 
					 | 
				
			||||||
 * of struct mgcp_client_conf changes in the future!
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	_mgcp_client_conf_init(conf);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void mgcp_client_handle_response(struct mgcp_client *mgcp,
 | 
					static void mgcp_client_handle_response(struct mgcp_client *mgcp,
 | 
				
			||||||
					struct mgcp_response_pending *pending,
 | 
										struct mgcp_response_pending *pending,
 | 
				
			||||||
					struct mgcp_response *response)
 | 
										struct mgcp_response *response)
 | 
				
			||||||
@@ -370,7 +345,7 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
	char codec_resp[64];
 | 
						char codec_resp[64];
 | 
				
			||||||
	int rc;
 | 
						enum mgcp_codecs codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define A_PTIME "a=ptime:"
 | 
					#define A_PTIME "a=ptime:"
 | 
				
			||||||
#define A_RTPMAP "a=rtpmap:"
 | 
					#define A_RTPMAP "a=rtpmap:"
 | 
				
			||||||
@@ -391,14 +366,9 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
 | 
				
			|||||||
			LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
 | 
								LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
 | 
				
			||||||
			return -ENOSPC;
 | 
								return -ENOSPC;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rc = map_str_to_codec(codec_resp);
 | 
							codec = map_str_to_codec(codec_resp);
 | 
				
			||||||
		if (rc < 0) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			     "Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		r->ptmap[r->ptmap_len].pt = pt;
 | 
							r->ptmap[r->ptmap_len].pt = pt;
 | 
				
			||||||
		r->ptmap[r->ptmap_len].codec = rc;
 | 
							r->ptmap[r->ptmap_len].codec = codec;
 | 
				
			||||||
		r->ptmap_len++;
 | 
							r->ptmap_len++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -486,15 +456,15 @@ static char *mgcp_find_section_end(char *string)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rc = strstr(string, "\n\n");
 | 
						rc = strstr(string, "\n\n");
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc + 2;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = strstr(string, "\n\r\n\r");
 | 
						rc = strstr(string, "\n\r\n\r");
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc + 4;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = strstr(string, "\r\n\r\n");
 | 
						rc = strstr(string, "\r\n\r\n");
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc + 4;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -705,14 +675,6 @@ int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
 | 
				
			|||||||
	r = talloc_zero(mgcp, struct mgcp_response);
 | 
						r = talloc_zero(mgcp, struct mgcp_response);
 | 
				
			||||||
	OSMO_ASSERT(r);
 | 
						OSMO_ASSERT(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Re-arm keepalive timer if enabled */
 | 
					 | 
				
			||||||
	if (OSMO_UNLIKELY(mgcp->conn_up == false)) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_NOTICE, "MGCP link to MGW now considered UP\n");
 | 
					 | 
				
			||||||
		mgcp->conn_up = true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (mgcp->actual.keepalive.timeout_sec > 0)
 | 
					 | 
				
			||||||
		osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = mgcp_response_parse_head(r, msg);
 | 
						rc = mgcp_response_parse_head(r, msg);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
 | 
				
			||||||
@@ -783,84 +745,13 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
 | 
				
			|||||||
		osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
							osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = write(fd->fd, msg->data, msg->len);
 | 
						ret = write(fd->fd, msg->data, msg->len);
 | 
				
			||||||
	if (OSMO_UNLIKELY(ret != msg->len))
 | 
						if (ret != msg->len)
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
				
			||||||
			osmo_sock_get_name2(fd->fd), errno, strerror(errno),
 | 
								osmo_sock_get_name2(fd->fd), errno, strerror(errno),
 | 
				
			||||||
			msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
								msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Re-arm the keepalive Tx timer: */
 | 
					 | 
				
			||||||
	if (mgcp->actual.keepalive.req_interval_sec > 0)
 | 
					 | 
				
			||||||
		osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
 | 
					 | 
				
			||||||
	if (rc > sizeof(endpoint) - 1) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
 | 
					 | 
				
			||||||
			sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (rc < 1) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return endpoint;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
					 | 
				
			||||||
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Format DLCX message (fire and forget) and send it off to the MGW */
 | 
					 | 
				
			||||||
static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct msgb *msgb_dlcx;
 | 
					 | 
				
			||||||
	struct mgcp_msg mgcp_msg_dlcx = {
 | 
					 | 
				
			||||||
		.verb = MGCP_VERB_DLCX,
 | 
					 | 
				
			||||||
		.presence = MGCP_MSG_PRESENCE_ENDPOINT,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
					 | 
				
			||||||
	msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
					 | 
				
			||||||
	mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Format AuditEndpoint message (fire and forget) and send it off to the MGW */
 | 
					 | 
				
			||||||
static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct msgb *msgb_auep;
 | 
					 | 
				
			||||||
	struct mgcp_msg mgcp_msg_auep = {
 | 
					 | 
				
			||||||
		.verb = MGCP_VERB_AUEP,
 | 
					 | 
				
			||||||
		.presence = MGCP_MSG_PRESENCE_ENDPOINT,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
 | 
					 | 
				
			||||||
	msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
 | 
					 | 
				
			||||||
	mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void mgcp_client_keepalive_tx_timer_cb(void *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp = (struct mgcp_client *)data;
 | 
					 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_INFO, "Triggering keepalive MGCP request\n");
 | 
					 | 
				
			||||||
	const char *epname = _mgcp_client_name_append_domain(mgcp, mgcp->actual.keepalive.req_endpoint_name);
 | 
					 | 
				
			||||||
	_mgcp_client_send_auep(mgcp, epname);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Re-arm the timer: */
 | 
					 | 
				
			||||||
	osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void mgcp_client_keepalive_rx_timer_cb(void *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp = (struct mgcp_client *)data;
 | 
					 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_ERROR, "MGCP link to MGW now considered DOWN (keepalive timeout, more than %u seconds with no answer from MGW)\n",
 | 
					 | 
				
			||||||
		mgcp->actual.keepalive.timeout_sec);
 | 
					 | 
				
			||||||
	mgcp->conn_up = false;
 | 
					 | 
				
			||||||
	/* TODO: Potentially time out all ongoing transactions for that MGW. Maybe based on VTY cfg? */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client *mgcp_client_init(void *ctx,
 | 
					struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			||||||
				     struct mgcp_client_conf *conf)
 | 
									     struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -873,6 +764,7 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&mgcp->responses_pending);
 | 
						INIT_LLIST_HEAD(&mgcp->responses_pending);
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp->next_trans_id = 1;
 | 
						mgcp->next_trans_id = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -905,34 +797,66 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	if (conf->description)
 | 
						if (conf->description)
 | 
				
			||||||
		mgcp->actual.description = talloc_strdup(mgcp, conf->description);
 | 
							mgcp->actual.description = talloc_strdup(mgcp, conf->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_wqueue_init(&mgcp->wq, 1024);
 | 
					 | 
				
			||||||
	mgcp->wq.read_cb = mgcp_do_read;
 | 
					 | 
				
			||||||
	mgcp->wq.write_cb = mgcp_do_write;
 | 
					 | 
				
			||||||
	osmo_fd_setup(&mgcp->wq.bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memcpy(&mgcp->actual.keepalive, &conf->keepalive, sizeof(conf->keepalive));
 | 
					 | 
				
			||||||
	osmo_timer_setup(&mgcp->keepalive_tx_timer, mgcp_client_keepalive_tx_timer_cb, mgcp);
 | 
					 | 
				
			||||||
	osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return mgcp;
 | 
						return mgcp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
				
			||||||
 | 
					static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Format DLCX message (fire and forget) and send it off to the MGW */
 | 
				
			||||||
 | 
					static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msgb_dlcx;
 | 
				
			||||||
 | 
						struct mgcp_msg mgcp_msg_dlcx = {
 | 
				
			||||||
 | 
							.verb = MGCP_VERB_DLCX,
 | 
				
			||||||
 | 
							.presence = MGCP_MSG_PRESENCE_ENDPOINT,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
				
			||||||
 | 
						msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
				
			||||||
 | 
						mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
						if (rc > sizeof(endpoint) - 1) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
 | 
				
			||||||
 | 
								sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rc < 1) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return endpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initialize client connection (opens socket)
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct reset_ep *reset_ep;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
	const char *epname;
 | 
						const char *epname;
 | 
				
			||||||
	bool some_dlcx_sent = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mgcp) {
 | 
						if (!mgcp) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_FATAL, "Client not initialized properly\n");
 | 
							LOGPMGW(mgcp, LOGL_FATAL, "Client not initialized properly\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_sock_init2_ofd(&mgcp->wq.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
 | 
						osmo_wqueue_init(wq, 1024);
 | 
				
			||||||
 | 
						wq->read_cb = mgcp_do_read;
 | 
				
			||||||
 | 
						wq->write_cb = mgcp_do_write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
				
			||||||
				 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
									 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
				
			||||||
				 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
									 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
@@ -944,7 +868,7 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		goto error_close_fd;
 | 
							goto error_close_fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(mgcp->wq.bfd.fd));
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If configured, send a DLCX message to the endpoints that are configured to
 | 
						/* If configured, send a DLCX message to the endpoints that are configured to
 | 
				
			||||||
	 * be reset on startup. Usually this is a wildcarded endpoint. */
 | 
						 * be reset on startup. Usually this is a wildcarded endpoint. */
 | 
				
			||||||
@@ -952,27 +876,11 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);
 | 
							epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_INFO, "Sending DLCX to: %s\n", epname);
 | 
							LOGPMGW(mgcp, LOGL_INFO, "Sending DLCX to: %s\n", epname);
 | 
				
			||||||
		_mgcp_client_send_dlcx(mgcp, epname);
 | 
							_mgcp_client_send_dlcx(mgcp, epname);
 | 
				
			||||||
		some_dlcx_sent = true;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp->actual.keepalive.req_interval_sec > 0) {
 | 
					 | 
				
			||||||
		if (!some_dlcx_sent) {
 | 
					 | 
				
			||||||
			/* Attempt an immediate probe to find out if link is UP or DOWN: */
 | 
					 | 
				
			||||||
			osmo_timer_schedule(&mgcp->keepalive_tx_timer, 0, 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* else: keepalive_tx_timer was already scheduled (if needed) down in the stack during Tx DLCX above */
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* Assume link is UP by default, so that this MGW can be selected: */
 | 
					 | 
				
			||||||
		mgcp->conn_up = true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp->actual.keepalive.timeout_sec > 0)
 | 
					 | 
				
			||||||
		osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
error_close_fd:
 | 
					error_close_fd:
 | 
				
			||||||
	close(mgcp->wq.bfd.fd);
 | 
						close(wq->bfd.fd);
 | 
				
			||||||
	mgcp->wq.bfd.fd = -1;
 | 
						wq->bfd.fd = -1;
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -996,18 +904,13 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Disarm keepalive Tx/Rx timer until next connect() */
 | 
					 | 
				
			||||||
	osmo_timer_del(&mgcp->keepalive_rx_timer);
 | 
					 | 
				
			||||||
	osmo_timer_del(&mgcp->keepalive_tx_timer);
 | 
					 | 
				
			||||||
	mgcp->conn_up = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wq = &mgcp->wq;
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
	osmo_wqueue_clear(wq);
 | 
						osmo_wqueue_clear(wq);
 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
				
			||||||
	if (osmo_fd_is_registered(&wq->bfd))
 | 
					 | 
				
			||||||
		osmo_fd_unregister(&wq->bfd);
 | 
					 | 
				
			||||||
	close(wq->bfd.fd);
 | 
						close(wq->bfd.fd);
 | 
				
			||||||
	wq->bfd.fd = -1;
 | 
						wq->bfd.fd = -1;
 | 
				
			||||||
 | 
						if (osmo_fd_is_registered(&wq->bfd))
 | 
				
			||||||
 | 
							osmo_fd_unregister(&wq->bfd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get the IP-Aaddress of the associated MGW as string.
 | 
					/*! Get the IP-Aaddress of the associated MGW as string.
 | 
				
			||||||
@@ -1103,8 +1006,11 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
 | 
				
			|||||||
	return epname;
 | 
						return epname;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending *mgcp_client_pending_add(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id,
 | 
					struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			||||||
						      mgcp_response_cb_t response_cb, void *priv)
 | 
										struct mgcp_client *mgcp,
 | 
				
			||||||
 | 
										mgcp_trans_id_t trans_id,
 | 
				
			||||||
 | 
										mgcp_response_cb_t response_cb,
 | 
				
			||||||
 | 
										void *priv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_response_pending *pending;
 | 
						struct mgcp_response_pending *pending;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1232,87 +1138,87 @@ static mgcp_trans_id_t mgcp_client_next_trans_id(struct mgcp_client *mgcp)
 | 
				
			|||||||
static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
					static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
	const char *codec;
 | 
						const char *codec;
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
						rc |= msgb_printf(msg, "L:");
 | 
				
			||||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR, "Message buffer too small, can not generate MGCP/SDP message\n"); \
 | 
					 | 
				
			||||||
			return -ENOBUFS; \
 | 
					 | 
				
			||||||
		} \
 | 
					 | 
				
			||||||
	} while (0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MSGB_PRINTF_OR_RET("L:");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->ptime)
 | 
						if (mgcp_msg->ptime)
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
 | 
							rc |= msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->codecs_len) {
 | 
						if (mgcp_msg->codecs_len) {
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" a:");
 | 
							rc |= msgb_printf(msg, " a:");
 | 
				
			||||||
		for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
							for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
			pt = mgcp_msg->codecs[i];
 | 
								pt = mgcp_msg->codecs[i];
 | 
				
			||||||
			codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
			if (!codec)
 | 
								if (!codec) {
 | 
				
			||||||
 | 
									msgb_free(msg);
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
 | 
								rc |= msgb_printf(msg, "%s", extract_codec_name(codec));
 | 
				
			||||||
			if (i < mgcp_msg->codecs_len - 1)
 | 
								if (i < mgcp_msg->codecs_len - 1)
 | 
				
			||||||
				MSGB_PRINTF_OR_RET(";");
 | 
									rc |= msgb_printf(msg, ";");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(",");
 | 
							rc |= msgb_printf(msg, ",");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MSGB_PRINTF_OR_RET(" nt:IN\r\n");
 | 
						rc |= msgb_printf(msg, " nt:IN\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "message buffer to small, can not generate MGCP message (LCO)\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
#undef MSGB_PRINTF_OR_RET
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
 | 
					/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
 | 
				
			||||||
static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
 | 
					static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
	char local_ip[INET6_ADDRSTRLEN];
 | 
						char local_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int local_ip_family, audio_ip_family;
 | 
						int local_ip_family, audio_ip_family;
 | 
				
			||||||
	const char *codec;
 | 
						const char *codec;
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
					 | 
				
			||||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
					 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Message buffer too small, can not generate MGCP message (SDP)\n"); \
 | 
					 | 
				
			||||||
			return -ENOBUFS; \
 | 
					 | 
				
			||||||
		} \
 | 
					 | 
				
			||||||
	} while (0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Add separator to mark the beginning of the SDP block */
 | 
						/* Add separator to mark the beginning of the SDP block */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("\r\n");
 | 
						rc |= msgb_printf(msg, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add SDP protocol version */
 | 
						/* Add SDP protocol version */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("v=0\r\n");
 | 
						rc |= msgb_printf(msg, "v=0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Determine local IP-Address */
 | 
						/* Determine local IP-Address */
 | 
				
			||||||
	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
						if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
			"Could not determine local IP-Address!\n");
 | 
								"Could not determine local IP-Address!\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	local_ip_family = osmo_ip_str_type(local_ip);
 | 
						local_ip_family = osmo_ip_str_type(local_ip);
 | 
				
			||||||
	if (local_ip_family == AF_UNSPEC)
 | 
						if (local_ip_family == AF_UNSPEC) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
						audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
				
			||||||
	if (audio_ip_family == AF_UNSPEC)
 | 
						if (audio_ip_family == AF_UNSPEC) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add owner/creator (SDP) */
 | 
						/* Add owner/creator (SDP) */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
						rc |= msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
				
			||||||
			  local_ip_family == AF_INET6 ? '6' : '4',
 | 
								  local_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
			  local_ip);
 | 
								  local_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add session name (none) */
 | 
						/* Add session name (none) */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("s=-\r\n");
 | 
						rc |= msgb_printf(msg, "s=-\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add RTP address and port */
 | 
						/* Add RTP address and port */
 | 
				
			||||||
	if (mgcp_msg->audio_port == 0) {
 | 
						if (mgcp_msg->audio_port == 0) {
 | 
				
			||||||
@@ -1327,20 +1233,20 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("c=IN IP%c %s\r\n",
 | 
						rc |= msgb_printf(msg, "c=IN IP%c %s\r\n",
 | 
				
			||||||
			  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
								  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
			  mgcp_msg->audio_ip);
 | 
								  mgcp_msg->audio_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add time description, active time (SDP) */
 | 
						/* Add time description, active time (SDP) */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("t=0 0\r\n");
 | 
						rc |= msgb_printf(msg, "t=0 0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
 | 
						rc |= msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
 | 
				
			||||||
	for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
						for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
		pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
							pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" %u", pt);
 | 
							rc |= msgb_printf(msg, " %u", pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("\r\n");
 | 
						rc |= msgb_printf(msg, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add optional codec parameters (fmtp) */
 | 
						/* Add optional codec parameters (fmtp) */
 | 
				
			||||||
	if (mgcp_msg->param_present) {
 | 
						if (mgcp_msg->param_present) {
 | 
				
			||||||
@@ -1350,9 +1256,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
				   continue;
 | 
									   continue;
 | 
				
			||||||
			pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
								pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
			if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
 | 
								if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
				MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt);
 | 
									rc |= msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
 | 
				
			||||||
			else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
 | 
								else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
				MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=0\r\n", pt);
 | 
									rc |= msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1367,18 +1273,25 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
			if (!codec)
 | 
								if (!codec) {
 | 
				
			||||||
 | 
									msgb_free(msg);
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MSGB_PRINTF_OR_RET("a=rtpmap:%u %s\r\n", pt, codec);
 | 
								rc |= msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->ptime)
 | 
						if (mgcp_msg->ptime)
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("a=ptime:%u\r\n", mgcp_msg->ptime);
 | 
							rc |= msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message (SDP)\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
#undef MSGB_PRINTF_OR_RET
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Generate an MGCP message
 | 
					/*! Generate an MGCP message
 | 
				
			||||||
@@ -1390,16 +1303,10 @@ 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);
 | 
						mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
 | 
				
			||||||
	uint32_t mandatory_mask;
 | 
						uint32_t mandatory_mask;
 | 
				
			||||||
	struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
 | 
						struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
	bool use_sdp = false;
 | 
						bool use_sdp = false;
 | 
				
			||||||
	char buf[32];
 | 
						char buf[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
					 | 
				
			||||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
					 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Message buffer too small, can not generate MGCP/SDP message\n"); \
 | 
					 | 
				
			||||||
			goto exit_error; \
 | 
					 | 
				
			||||||
		} \
 | 
					 | 
				
			||||||
	} while (0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg->l2h = msg->data;
 | 
						msg->l2h = msg->data;
 | 
				
			||||||
	msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
 | 
						msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1407,70 +1314,75 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	switch (mgcp_msg->verb) {
 | 
						switch (mgcp_msg->verb) {
 | 
				
			||||||
	case MGCP_VERB_CRCX:
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
		mandatory_mask = MGCP_CRCX_MANDATORY;
 | 
							mandatory_mask = MGCP_CRCX_MANDATORY;
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("CRCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "CRCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_MDCX:
 | 
						case MGCP_VERB_MDCX:
 | 
				
			||||||
		mandatory_mask = MGCP_MDCX_MANDATORY;
 | 
							mandatory_mask = MGCP_MDCX_MANDATORY;
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("MDCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "MDCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_DLCX:
 | 
						case MGCP_VERB_DLCX:
 | 
				
			||||||
		mandatory_mask = MGCP_DLCX_MANDATORY;
 | 
							mandatory_mask = MGCP_DLCX_MANDATORY;
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("DLCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "DLCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_AUEP:
 | 
						case MGCP_VERB_AUEP:
 | 
				
			||||||
		mandatory_mask = MGCP_AUEP_MANDATORY;
 | 
							mandatory_mask = MGCP_AUEP_MANDATORY;
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("AUEP %u", trans_id);
 | 
							rc |= msgb_printf(msg, "AUEP %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_RSIP:
 | 
						case MGCP_VERB_RSIP:
 | 
				
			||||||
		mandatory_mask = MGCP_RSIP_MANDATORY;
 | 
							mandatory_mask = MGCP_RSIP_MANDATORY;
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("RSIP %u", trans_id);
 | 
							rc |= msgb_printf(msg, "RSIP %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Invalid command verb, can not generate MGCP message\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Invalid command verb, can not generate MGCP message\n");
 | 
				
			||||||
		goto exit_error;
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if mandatory fields are missing */
 | 
						/* Check if mandatory fields are missing */
 | 
				
			||||||
	if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
 | 
						if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
			"One or more missing mandatory fields, can not generate MGCP message\n");
 | 
								"One or more missing mandatory fields, can not generate MGCP message\n");
 | 
				
			||||||
		goto exit_error;
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add endpoint name */
 | 
						/* Add endpoint name */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
 | 
				
			||||||
		if (strlen(mgcp_msg->endpoint) <= 0) {
 | 
							if (strlen(mgcp_msg->endpoint) <= 0) {
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Empty endpoint name, can not generate MGCP message\n");
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Empty endpoint name, can not generate MGCP message\n");
 | 
				
			||||||
			goto exit_error;
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (strstr(mgcp_msg->endpoint, "@") == NULL) {
 | 
							if (strstr(mgcp_msg->endpoint, "@") == NULL) {
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR,
 | 
								LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
				"Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
									"Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
				
			||||||
				mgcp_msg->endpoint);
 | 
									mgcp_msg->endpoint);
 | 
				
			||||||
			goto exit_error;
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" %s", mgcp_msg->endpoint);
 | 
							rc |= msgb_printf(msg, " %s", mgcp_msg->endpoint);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add protocol version */
 | 
						/* Add protocol version */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET(" MGCP 1.0\r\n");
 | 
						rc |= msgb_printf(msg, " MGCP 1.0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add call id */
 | 
						/* Add call id */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("C: %x\r\n", mgcp_msg->call_id);
 | 
							rc |= msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add connection id */
 | 
						/* Add connection id */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
 | 
				
			||||||
		if (strlen(mgcp_msg->conn_id) <= 0) {
 | 
							if (strlen(mgcp_msg->conn_id) <= 0) {
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Empty connection id, can not generate MGCP message\n");
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Empty connection id, can not generate MGCP message\n");
 | 
				
			||||||
			goto exit_error;
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("I: %s\r\n", mgcp_msg->conn_id);
 | 
							rc |= msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Using SDP makes sense when a valid IP/Port combination is specified,
 | 
						/* Using SDP makes sense when a valid IP/Port combination is specifiec,
 | 
				
			||||||
	 * if we do not know this information yet, we fall back to LCO */
 | 
						 * if we do not know this information yet, we fall back to LCO */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
 | 
				
			||||||
	    && mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)
 | 
						    && mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)
 | 
				
			||||||
@@ -1480,20 +1392,21 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	if (!use_sdp
 | 
						if (!use_sdp
 | 
				
			||||||
	    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
						    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
				
			||||||
		|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
							|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
				
			||||||
		if (add_lco(msg, mgcp_msg) < 0) {
 | 
						        if (add_lco(msg, mgcp_msg) < 0)
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Failed to add LCO, can not generate MGCP message\n");
 | 
								return NULL;
 | 
				
			||||||
			goto exit_error;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add mode */
 | 
						/* Add mode */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
 | 
				
			||||||
		MSGB_PRINTF_OR_RET("M: %s\r\n", mgcp_client_cmode_name(mgcp_msg->conn_mode));
 | 
							rc |=
 | 
				
			||||||
 | 
							    msgb_printf(msg, "M: %s\r\n",
 | 
				
			||||||
 | 
									mgcp_client_cmode_name(mgcp_msg->conn_mode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add X-Osmo-IGN */
 | 
						/* Add X-Osmo-IGN */
 | 
				
			||||||
	if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
 | 
						if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
 | 
				
			||||||
	    && (mgcp_msg->x_osmo_ign != 0))
 | 
						    && (mgcp_msg->x_osmo_ign != 0))
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
							rc |=
 | 
				
			||||||
 | 
							    msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
									mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add X-Osmo-Osmux */
 | 
						/* Add X-Osmo-Osmux */
 | 
				
			||||||
@@ -1501,10 +1414,12 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
		if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
 | 
							if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Wrong Osmux CID %d, can not generate MGCP message\n",
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Wrong Osmux CID %d, can not generate MGCP message\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_osmux_cid);
 | 
									mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
			goto exit_error;
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
 | 
							snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
 | 
							rc |=
 | 
				
			||||||
 | 
							    msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
 | 
									mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1513,18 +1428,17 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	if (use_sdp
 | 
						if (use_sdp
 | 
				
			||||||
	    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
						    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
				
			||||||
		|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
							|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
				
			||||||
		if (add_sdp(msg, mgcp_msg, mgcp) < 0) {
 | 
						        if (add_sdp(msg, mgcp_msg, mgcp) < 0)
 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_ERROR, "Failed to add SDP, can not generate MGCP message\n");
 | 
								return NULL;
 | 
				
			||||||
			goto exit_error;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							msg = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
 | 
					 | 
				
			||||||
exit_error:
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
#undef MSGB_PRINTF_OR_RET
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Retrieve the MGCP transaction ID from a msgb generated by mgcp_msg_gen()
 | 
					/*! Retrieve the MGCP transaction ID from a msgb generated by mgcp_msg_gen()
 | 
				
			||||||
@@ -1548,7 +1462,6 @@ const struct value_string mgcp_client_connection_mode_strs[] = {
 | 
				
			|||||||
	{ MGCP_CONN_RECV_SEND, "sendrecv" },
 | 
						{ MGCP_CONN_RECV_SEND, "sendrecv" },
 | 
				
			||||||
	{ MGCP_CONN_SEND_ONLY, "sendonly" },
 | 
						{ MGCP_CONN_SEND_ONLY, "sendonly" },
 | 
				
			||||||
	{ MGCP_CONN_RECV_ONLY, "recvonly" },
 | 
						{ MGCP_CONN_RECV_ONLY, "recvonly" },
 | 
				
			||||||
	{ MGCP_CONN_CONFECHO, "confecho" },
 | 
					 | 
				
			||||||
	{ MGCP_CONN_LOOPBACK, "loopback" },
 | 
						{ MGCP_CONN_LOOPBACK, "loopback" },
 | 
				
			||||||
	{ 0, NULL }
 | 
						{ 0, NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,30 +173,6 @@ const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
 | 
				
			|||||||
	return osmo_fsm_inst_name(ep->fi);
 | 
						return osmo_fsm_inst_name(ep->fi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get "local endpoint name" part of the endpoint name: (local-endpoint-name@domain-name)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \param ep  The MGCP Endpoint
 | 
					 | 
				
			||||||
 * \returns the local endpoint name if found, NULL on error.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static char buf[1024];
 | 
					 | 
				
			||||||
	const char *sep;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(ep);
 | 
					 | 
				
			||||||
	sep = strchr(ep->endpoint, '@');
 | 
					 | 
				
			||||||
	if (!sep) {
 | 
					 | 
				
			||||||
		OSMO_STRLCPY_ARRAY(buf, ep->endpoint);
 | 
					 | 
				
			||||||
		return buf;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (sep - ep->endpoint >= sizeof(buf))
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memcpy(buf, ep->endpoint, sep - ep->endpoint);
 | 
					 | 
				
			||||||
	buf[sep - ep->endpoint] = '\0';
 | 
					 | 
				
			||||||
	return buf;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
					const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
						/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,11 +75,6 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
 | 
				
			|||||||
	pool->mgcp_client_single = mgcp_client;
 | 
						pool->mgcp_client_single = mgcp_client;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return llist_empty(&pool->member_list);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Lookup the selected MGCP client config by its reference number */
 | 
					/*! Lookup the selected MGCP client config by its reference number */
 | 
				
			||||||
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -94,7 +89,7 @@ struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_c
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
					/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
				
			||||||
 * pool member that is suitable (is not blocked, has a client with a working link, has a low load). */
 | 
					 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
				
			||||||
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
					static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
@@ -103,15 +98,14 @@ static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
		n_pool_members++;
 | 
							n_pool_members++;
 | 
				
			||||||
		bool conn_up = pool_member->client && pool_member->client->conn_up;
 | 
							if (pool_member->blocked == false && pool_member->client) {
 | 
				
			||||||
		if (pool_member->blocked == false && conn_up) {
 | 
					 | 
				
			||||||
			if (!pool_member_picked)
 | 
								if (!pool_member_picked)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
			else if (pool_member_picked->refcount > pool_member->refcount)
 | 
								else if (pool_member_picked->refcount > pool_member->refcount)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u, link=%u)\n",
 | 
								LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u)\n",
 | 
				
			||||||
				 __func__, pool_member->nr, pool_member->blocked, !!pool_member->client, conn_up);
 | 
									 __func__, pool_member->nr, pool_member->blocked, !!pool_member->client);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/* MGCP client interface to quagga VTY */
 | 
					/* MGCP client interface to quagga VTY */
 | 
				
			||||||
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
					 * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
				
			||||||
 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
 | 
					 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * (C) 2009-2011 by Holger Hans Peter Freyther
 | 
					 * (C) 2009-2011 by Holger Hans Peter Freyther
 | 
				
			||||||
@@ -28,7 +28,6 @@
 | 
				
			|||||||
#include <osmocom/vty/command.h>
 | 
					#include <osmocom/vty/command.h>
 | 
				
			||||||
#include <osmocom/vty/misc.h>
 | 
					#include <osmocom/vty/misc.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
@@ -49,43 +48,19 @@ static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
 | 
				
			|||||||
/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
 | 
					/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
 | 
				
			||||||
static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
 | 
					static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
 | 
					struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
						if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
				
			||||||
		return vty->index;
 | 
							return vty->index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Global single MGCP config, deprecated: */
 | 
						/* Global single MGCP config, deprecated: */
 | 
				
			||||||
	vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
						vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
				
			||||||
		"You should consider reading the User Manual and migrating to 'mgw' node.%s",
 | 
							"You should consider reading User Manual and migrating to 'mgw' node.%s",
 | 
				
			||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return global_mgcp_client_conf;
 | 
						return global_mgcp_client_conf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_client *get_mgcp_client(struct vty *vty)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
					 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node) {
 | 
					 | 
				
			||||||
		llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
					 | 
				
			||||||
			/* Find matching the conf pointer: */
 | 
					 | 
				
			||||||
			if (&pool_member->conf != conf)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			return pool_member->client;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Global single MGCP config, deprecated: */
 | 
					 | 
				
			||||||
	vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
					 | 
				
			||||||
		"You should consider reading the User Manual and migrating to 'mgw' node.%s",
 | 
					 | 
				
			||||||
		VTY_NEWLINE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* There's no way to obtain the struct mgcp_client in old interface, but anyway it's deprecated. */
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "local-ip " VTY_IPV46_CMD,
 | 
					      "local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      "local bind to connect to MGW from\n"
 | 
					      "local bind to connect to MGW from\n"
 | 
				
			||||||
@@ -305,91 +280,6 @@ ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
 | 
				
			|||||||
      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
					      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_mgw_keepalive_req_interval,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_keepalive_req_interval_cmd,
 | 
					 | 
				
			||||||
      "keepalive request-interval <0-4294967295>",
 | 
					 | 
				
			||||||
      "Monitor if the MGCP link against MGW is still usable\n"
 | 
					 | 
				
			||||||
      "Send an MGCP command to the MGW at given interval if no other commands are sent\n"
 | 
					 | 
				
			||||||
      "The interval at which send MGCP commands (s), 0 to disable\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conf->keepalive.req_interval_sec = atoi(argv[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mgcp)
 | 
					 | 
				
			||||||
		return CMD_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If client already exists, apply the change immediately if possible: */
 | 
					 | 
				
			||||||
	mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
 | 
					 | 
				
			||||||
	if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
 | 
					 | 
				
			||||||
		if (mgcp->actual.keepalive.req_interval_sec > 0) {
 | 
					 | 
				
			||||||
			/* Re-schedule: */
 | 
					 | 
				
			||||||
			osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (osmo_timer_pending(&mgcp->keepalive_tx_timer))
 | 
					 | 
				
			||||||
				osmo_timer_del(&mgcp->keepalive_tx_timer);
 | 
					 | 
				
			||||||
			/* Assume link is UP by default, so that this MGW can be selected: */
 | 
					 | 
				
			||||||
			mgcp->conn_up = true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} /* else: wait until connect() to do first scheduling */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgw_mgw_keepalive_req_endpoint,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_keepalive_req_endpoint_cmd,
 | 
					 | 
				
			||||||
      "keepalive request-endpoint NAME",
 | 
					 | 
				
			||||||
      "Monitor if the MGCP link against MGW is still usable\n"
 | 
					 | 
				
			||||||
      "Use a given endpoint name when sending an MGCP command to the MGW for keepalive purposes\n"
 | 
					 | 
				
			||||||
      "The name of the endpoint to use\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_STRLCPY_ARRAY(conf->keepalive.req_endpoint_name, argv[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mgcp)
 | 
					 | 
				
			||||||
		return CMD_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If client already exists, apply the change immediately if possible: */
 | 
					 | 
				
			||||||
	OSMO_STRLCPY_ARRAY(mgcp->actual.keepalive.req_endpoint_name, argv[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgw_mgw_keepalive_timeout,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_keepalive_timeout_cmd,
 | 
					 | 
				
			||||||
      "keepalive timeout <0-4294967295>",
 | 
					 | 
				
			||||||
      "Monitor if the MGCP link against MGW is still usable\n"
 | 
					 | 
				
			||||||
      "Consider the link to the MGW to be down after time without receiving any message from it\n"
 | 
					 | 
				
			||||||
      "The timeout (s), 0 to disable\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conf->keepalive.timeout_sec = atoi(argv[0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mgcp)
 | 
					 | 
				
			||||||
		return CMD_SUCCESS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If client already exists, apply the change immediately if possible: */
 | 
					 | 
				
			||||||
	mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
 | 
					 | 
				
			||||||
	if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
 | 
					 | 
				
			||||||
		if (mgcp->actual.keepalive.timeout_sec > 0) {
 | 
					 | 
				
			||||||
			/* Re-schedule: */
 | 
					 | 
				
			||||||
			osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (osmo_timer_pending(&mgcp->keepalive_rx_timer))
 | 
					 | 
				
			||||||
				osmo_timer_del(&mgcp->keepalive_rx_timer);
 | 
					 | 
				
			||||||
			/* Assume link is UP by default, so that this MGW can be selected: */
 | 
					 | 
				
			||||||
			mgcp->conn_up = true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} /* else: wait until connect() to do first scheduling */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
					static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *addr;
 | 
						const char *addr;
 | 
				
			||||||
@@ -427,17 +317,6 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
 | 
				
			|||||||
	llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
				
			||||||
		vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
 | 
							vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conf->keepalive.req_interval_sec != 0)
 | 
					 | 
				
			||||||
		vty_out(vty, "%s%skeepalive request-interval %u%s", indent, mgw_prefix,
 | 
					 | 
				
			||||||
			conf->keepalive.req_interval_sec, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	if (strncmp(conf->keepalive.req_endpoint_name, MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP,
 | 
					 | 
				
			||||||
		    sizeof(conf->keepalive.req_endpoint_name)) != 0)
 | 
					 | 
				
			||||||
		vty_out(vty, "%s%skeepalive request-endpoint %s%s", indent,  mgw_prefix,
 | 
					 | 
				
			||||||
			conf->keepalive.req_endpoint_name, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	if (conf->keepalive.timeout_sec != 0)
 | 
					 | 
				
			||||||
		vty_out(vty, "%s%skeepalive timeout %u%s", indent,  mgw_prefix,
 | 
					 | 
				
			||||||
			conf->keepalive.timeout_sec, VTY_NEWLINE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -468,9 +347,6 @@ static void vty_init_common(void *talloc_ctx, int node)
 | 
				
			|||||||
	install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_keepalive_req_interval_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_keepalive_req_endpoint_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_keepalive_timeout_cmd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fsm_vty_add_cmds();
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -677,13 +553,8 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
						llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
				
			||||||
		const struct mgcp_client *cli = pool_member->client;
 | 
					 | 
				
			||||||
		vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
							vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "%%   MGCP link:     %s,%s%s",
 | 
							vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
				
			||||||
			cli && cli->wq.bfd.fd != -1 ? "connected" : "disconnected",
 | 
					 | 
				
			||||||
			cli && cli->conn_up ?
 | 
					 | 
				
			||||||
				((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
 | 
					 | 
				
			||||||
				"DOWN",
 | 
					 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "%%   service:       %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
 | 
							vty_out(vty, "%%   service:       %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "%%   ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
 | 
							vty_out(vty, "%%   ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,12 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_LIBS) \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -276,6 +276,87 @@ error:
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the given codec is applicable on the specified endpoint
 | 
				
			||||||
 | 
					 * Helper function for mgcp_codec_decide() */
 | 
				
			||||||
 | 
					static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* A codec name must be set, if not, this might mean that the codec
 | 
				
			||||||
 | 
						 * (payload type) that was assigned is unknown to us so we must stop
 | 
				
			||||||
 | 
						 * here. */
 | 
				
			||||||
 | 
						if (!strlen(codec->subtype_name))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: implement meaningful checks to make sure that the given codec
 | 
				
			||||||
 | 
						 * is compatible with the given endpoint */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Decide for one suitable codec
 | 
				
			||||||
 | 
					 *  \param[in] conn related rtp-connection.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						bool codec_assigned = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp = conn->conn->endp;
 | 
				
			||||||
 | 
						rtp = &conn->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This function works on the results the SDP/LCO parser has extracted
 | 
				
			||||||
 | 
						 * from the MGCP message. The goal is to select a suitable codec for
 | 
				
			||||||
 | 
						 * the given connection. When transcoding is available, the first codec
 | 
				
			||||||
 | 
						 * from the codec list is taken without further checking. When
 | 
				
			||||||
 | 
						 * transcoding is not available, then the choice must be made more
 | 
				
			||||||
 | 
						 * carefully. Each codec in the list is checked until one is found that
 | 
				
			||||||
 | 
						 * is rated compatible. The rating is done by the helper function
 | 
				
			||||||
 | 
						 * is_codec_compatible(), which does the actual checking. */
 | 
				
			||||||
 | 
						for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
				
			||||||
 | 
							/* When no transcoding is available, avoid codecs that would
 | 
				
			||||||
 | 
							 * require transcoding. */
 | 
				
			||||||
 | 
							if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
 | 
				
			||||||
 | 
								     rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rtp->codec = &rtp->codecs[i];
 | 
				
			||||||
 | 
							codec_assigned = true;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: To the reviewes: This is problematic. I do not get why we
 | 
				
			||||||
 | 
						 * need to reset the packet_duration_ms depending on the codec
 | 
				
			||||||
 | 
						 * selection. I thought it were all 20ms? Is this to address some
 | 
				
			||||||
 | 
						 * cornercase. (This piece of code was in the code path before,
 | 
				
			||||||
 | 
						 * together with the note: "TODO/XXX: Store this per codec and derive
 | 
				
			||||||
 | 
						 * it on use" */
 | 
				
			||||||
 | 
						if (codec_assigned) {
 | 
				
			||||||
 | 
							if (rtp->maximum_packet_time >= 0
 | 
				
			||||||
 | 
							    && rtp->maximum_packet_time * rtp->codec->frame_duration_den >
 | 
				
			||||||
 | 
							    rtp->codec->frame_duration_num * 1500)
 | 
				
			||||||
 | 
								rtp->packet_duration_ms = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (codec->param_present == false)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (!codec->param.amr_octet_aligned_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
					/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
				
			||||||
 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
					 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
				
			||||||
 * Media Type Registration":
 | 
					 * Media Type Registration":
 | 
				
			||||||
@@ -295,15 +376,10 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
	return codec->param.amr_octet_aligned;
 | 
						return codec->param.amr_octet_aligned;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare two codecs, all parameters must match up */
 | 
					/* Compare two codecs, all parameters must match up, except for the payload type
 | 
				
			||||||
 | 
					 * number. */
 | 
				
			||||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
 | 
					 | 
				
			||||||
	 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
 | 
					 | 
				
			||||||
	 * payload type numbers. Also the audio_name is not checked since it is already parsed into subtype_name, rate,
 | 
					 | 
				
			||||||
	 * and channels, which are checked. */
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (codec_a->rate != codec_b->rate)
 | 
						if (codec_a->rate != codec_b->rate)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->channels != codec_b->channels)
 | 
						if (codec_a->channels != codec_b->channels)
 | 
				
			||||||
@@ -312,163 +388,61 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
						if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* AMR payload may be formatted in two different payload formats, it is still the same codec but since the
 | 
					 | 
				
			||||||
	 * formatting of the payload is different, conversation is required, so we must treat it as a different
 | 
					 | 
				
			||||||
	 * codec here. */
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, "AMR") == 0) {
 | 
					 | 
				
			||||||
		if (mgcp_codec_amr_is_octet_aligned(codec_a) != mgcp_codec_amr_is_octet_aligned(codec_b))
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
 | 
					 | 
				
			||||||
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
 | 
					 | 
				
			||||||
	 * translate between different payload formats as long as the encoded voice data itself does not change.
 | 
					 | 
				
			||||||
	 * Therefore we must insist on equal codecs but still allow different payload formatting. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* In 3G IuUP, AMR may be encapsulated in IuFP, this means even though the codec name and negotiated rate is
 | 
					 | 
				
			||||||
	 * different, the formatting can still be converted by OsmoMGW. Therefore we won't insist on equal
 | 
					 | 
				
			||||||
	 * subtype_name and rate if we detect IuFP and AMR is used on the same tandem. */
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, "AMR") == 0 && strcmp(codec_b->subtype_name, "VND.3GPP.IUFP") == 0)
 | 
					 | 
				
			||||||
		goto iufp;
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, "VND.3GPP.IUFP") == 0 && strcmp(codec_b->subtype_name, "AMR") == 0)
 | 
					 | 
				
			||||||
		goto iufp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
						if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->rate != codec_b->rate)
 | 
					
 | 
				
			||||||
		return false;
 | 
						/* Note: AMR allows to set the RTP payload format to octet-aligned or bandwith-efficient (octet-aligned=0)
 | 
				
			||||||
iufp:
 | 
						 * via SDP. This difference concerns payload format only, but not the actual codec. It is not a difference
 | 
				
			||||||
	if (codec_a->channels != codec_b->channels)
 | 
						 * within the meaning of this function. */
 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (codec_a->frame_duration_num != codec_b->frame_duration_num)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
					/*! Translate a given payload type number that belongs to the packet of a
 | 
				
			||||||
 | 
					 *  source connection to the equivalent payload type number that matches the
 | 
				
			||||||
 | 
					 *  configuration of a destination connection.
 | 
				
			||||||
 | 
					 *  \param[in] conn_src related source rtp-connection.
 | 
				
			||||||
 | 
					 *  \param[in] conn_dst related destination rtp-connection.
 | 
				
			||||||
 | 
					 *  \param[in] payload_type number from the source packet or source connection.
 | 
				
			||||||
 | 
					 *  \returns translated payload type number on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end;
 | 
						struct mgcp_rtp_end *rtp_src;
 | 
				
			||||||
 | 
						struct mgcp_rtp_end *rtp_dst;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec_src = NULL;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec_dst = NULL;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_end = &conn->end;
 | 
						rtp_src = &conn_src->end;
 | 
				
			||||||
 | 
						rtp_dst = &conn_dst->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
						/* Find the codec information that is used on the source side */
 | 
				
			||||||
	 * the first run we will look for an exact match. */
 | 
						codecs_assigned = rtp_src->codecs_assigned;
 | 
				
			||||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < codecs_assigned; i++) {
 | 
				
			||||||
		if (codecs_same(codec, &rtp_end->codecs[i])) {
 | 
							if (payload_type == rtp_src->codecs[i].payload_type) {
 | 
				
			||||||
			return &rtp_end->codecs[i];
 | 
								codec_src = &rtp_src->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!codec_src)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						/* Use the codec information from the source and try to find the
 | 
				
			||||||
}
 | 
						 * equivalent of it on the destination side */
 | 
				
			||||||
 | 
						codecs_assigned = rtp_dst->codecs_assigned;
 | 
				
			||||||
/* For a given codec, find a convertible codec in the given connection. */
 | 
					 | 
				
			||||||
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec_convertible = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtp_end = &conn->end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
					 | 
				
			||||||
	 * the first run we will look for an exact match. */
 | 
					 | 
				
			||||||
	codec_convertible = mgcp_codec_find_same(conn, codec);
 | 
					 | 
				
			||||||
	if (codec_convertible)
 | 
					 | 
				
			||||||
		return codec_convertible;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
 | 
					 | 
				
			||||||
	 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
 | 
					 | 
				
			||||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < codecs_assigned; i++) {
 | 
				
			||||||
		if (codecs_convertible(codec, &rtp_end->codecs[i])) {
 | 
							if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
 | 
				
			||||||
			codec_convertible = &rtp_end->codecs[i];
 | 
								codec_dst = &rtp_dst->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!codec_dst)
 | 
				
			||||||
	return codec_convertible;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
 | 
					 | 
				
			||||||
 *  a tentative decision is made.
 | 
					 | 
				
			||||||
 *  \param[inout] conn_src related rtp-connection.
 | 
					 | 
				
			||||||
 *  \param[inout] conn_dst related destination rtp-connection (NULL if not present).
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* In case no destination connection is available (yet), or in case the destination connection exists but has
 | 
					 | 
				
			||||||
	 * no codecs assigned, we are forced to make a simple tentative decision:
 | 
					 | 
				
			||||||
	 * We just use the first codec of the source connection (conn_src) */
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
 | 
					 | 
				
			||||||
	if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
 | 
					 | 
				
			||||||
		if (conn_src->end.codecs_assigned >= 1) {
 | 
					 | 
				
			||||||
			conn_src->end.codec = &conn_src->end.codecs[0];
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
 | 
						return codec_dst->payload_type;
 | 
				
			||||||
	 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
 | 
					 | 
				
			||||||
	 * required. */
 | 
					 | 
				
			||||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
					 | 
				
			||||||
		struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, &conn_src->end.codecs[i]);
 | 
					 | 
				
			||||||
		if (codec_conn_dst) {
 | 
					 | 
				
			||||||
			/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
 | 
					 | 
				
			||||||
			 * sides. We now set this codec on both connections. */
 | 
					 | 
				
			||||||
			conn_dst->end.codec = codec_conn_dst;
 | 
					 | 
				
			||||||
			conn_src->end.codec = mgcp_codec_find_same(conn_src, codec_conn_dst);
 | 
					 | 
				
			||||||
			OSMO_ASSERT(conn_src->end.codec);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
 | 
					 | 
				
			||||||
	 * to convert. */
 | 
					 | 
				
			||||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
					 | 
				
			||||||
		struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, &conn_src->end.codecs[i]);
 | 
					 | 
				
			||||||
		if (codec_conn_dst) {
 | 
					 | 
				
			||||||
			/* We found the a codec that we are able to convert on both sides. We now set this codec on both
 | 
					 | 
				
			||||||
			 * connections. */
 | 
					 | 
				
			||||||
			conn_dst->end.codec = codec_conn_dst;
 | 
					 | 
				
			||||||
			conn_src->end.codec = codec_find_convertible(conn_src, codec_conn_dst);
 | 
					 | 
				
			||||||
			OSMO_ASSERT(conn_src->end.codec);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
					 | 
				
			||||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (codec->param_present == false)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (!codec->param.amr_octet_aligned_present)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Find the payload type number configured for a specific codec by SDP.
 | 
					/* Find the payload type number configured for a specific codec by SDP.
 | 
				
			||||||
@@ -478,7 +452,8 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
 * \param subtype_name  SDP codec name without parameters (e.g. "AMR").
 | 
					 * \param subtype_name  SDP codec name without parameters (e.g. "AMR").
 | 
				
			||||||
 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
					 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
				
			||||||
 *                  with incrementing match_nr.
 | 
					 *                  with incrementing match_nr.
 | 
				
			||||||
 * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
 | 
					 * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr)
 | 
													const char *subtype_name, unsigned int match_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -494,26 +469,3 @@ const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Lookup a codec that is assigned to a connection by its payload type number.
 | 
					 | 
				
			||||||
 *  \param[in] conn related rtp-connection.
 | 
					 | 
				
			||||||
 *  \param[in] payload_type number of the codec to look up.
 | 
					 | 
				
			||||||
 *  \returns pointer to codec struct on success, NULL on failure. */
 | 
					 | 
				
			||||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end = &conn->end;
 | 
					 | 
				
			||||||
	unsigned int codecs_assigned = rtp_end->codecs_assigned;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec = NULL;
 | 
					 | 
				
			||||||
	size_t i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
					 | 
				
			||||||
		if (payload_type == rtp_end->codecs[i].payload_type) {
 | 
					 | 
				
			||||||
			codec = &rtp_end->codecs[i];
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return codec;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,8 +173,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do not allow more than the maximum number of connections */
 | 
						/* Do not allow more then two connections */
 | 
				
			||||||
	if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns)
 | 
						if (llist_count(&endp->conns) >= endp->type->max_conns)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Create new connection and add it to the list */
 | 
						/* Create new connection and add it to the list */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,7 +222,7 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
 | 
				
			|||||||
	osmo_i460_mux_enqueue(endp->e1.schan, msg);
 | 
						osmo_i460_mux_enqueue(endp->e1.schan, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
 | 
					/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */
 | 
				
			||||||
static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
 | 
					static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
 | 
				
			||||||
				  unsigned int num_bits)
 | 
									  unsigned int num_bits)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -309,8 +309,8 @@ skip:
 | 
				
			|||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* handle outgoing E1 traffic */
 | 
					/* Function to handle outgoing E1 traffic */
 | 
				
			||||||
static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
					static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
 | 
						struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
 | 
				
			||||||
	uint8_t *ptr;
 | 
						uint8_t *ptr;
 | 
				
			||||||
@@ -359,17 +359,19 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
	osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
 | 
						osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Trigger sending of pending E1 traffic */
 | 
						/* Trigger sending of pending E1 traffic */
 | 
				
			||||||
	e1_send_ts_frame(ts, trunk);
 | 
						e1_send(ts, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* e1inp_rx_ts(), the caller of this callback does not free() msgb. */
 | 
						/* e1inp_rx_ts() does not free() msgb */
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
					static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*! One E1 timeslot may serve multiple I.460 subslots. The timeslot is opened as soon as an I.460 subslot is
 | 
						/*! Each timeslot needs only to be configured once. The Timeslot then
 | 
				
			||||||
	 *  opened and will stay open until the last I.460 subslot is closed (see e1_close below). This function must
 | 
						 *  stays open and permanently receives data. It is then up to the
 | 
				
			||||||
	 *  be called any time a new I.460 subslot is opened in order to maintain constancy of the ts_usecount counter. */
 | 
						 *  I.460 demultiplexer to add/remove subchannels as needed. It is
 | 
				
			||||||
 | 
						 *  allowed to call this function multiple times since we check if the
 | 
				
			||||||
 | 
						 *  timeslot is already configured. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct e1inp_line *e1_line;
 | 
						struct e1inp_line *e1_line;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -377,14 +379,12 @@ static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
	OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
						OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
				
			||||||
	cfg = trunk->cfg;
 | 
						cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trunk->e1.ts_usecount[ts_nr - 1] > 0) {
 | 
						if (trunk->e1.ts_in_use[ts_nr - 1]) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up and in use by %u subslot(s), using it as it is...\n",
 | 
							LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
 | 
				
			||||||
			  ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
 | 
					 | 
				
			||||||
		trunk->e1.ts_usecount[ts_nr - 1]++;
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find E1 line */
 | 
						/* Get E1 line */
 | 
				
			||||||
	e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
						e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
				
			||||||
	if (!e1_line) {
 | 
						if (!e1_line) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
 | 
				
			||||||
@@ -401,61 +401,12 @@ static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	rc = e1inp_line_update(e1_line);
 | 
						rc = e1inp_line_update(e1_line);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", ts_nr);
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
 | 
						LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
 | 
				
			||||||
	trunk->e1.ts_usecount[ts_nr - 1]++;
 | 
						trunk->e1.ts_in_use[ts_nr - 1] = true;
 | 
				
			||||||
	OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int e1_close(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* See also comment above (e1_open). This function must be called any time an I.460 subslot is closed */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct e1inp_line *e1_line;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
					 | 
				
			||||||
	cfg = trunk->cfg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (trunk->e1.ts_usecount[ts_nr - 1] > 1) {
 | 
					 | 
				
			||||||
		trunk->e1.ts_usecount[ts_nr - 1]--;
 | 
					 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u still in use by %u other subslot(s), leaving it open...\n",
 | 
					 | 
				
			||||||
			  ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	} else if (trunk->e1.ts_usecount[ts_nr - 1] == 0) {
 | 
					 | 
				
			||||||
		/* This should not be as it means we close the timeslot too often. */
 | 
					 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "E1 timeslot %u already closed, leaving it as it is...\n", ts_nr);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Find E1 line */
 | 
					 | 
				
			||||||
	e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
					 | 
				
			||||||
	if (!e1_line) {
 | 
					 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
 | 
					 | 
				
			||||||
			  trunk->e1.vty_line_nr);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Release E1 timeslot */
 | 
					 | 
				
			||||||
	rc = e1inp_ts_config_none(&e1_line->ts[ts_nr - 1], e1_line);
 | 
					 | 
				
			||||||
	if (rc < 0) {
 | 
					 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to disable E1 timeslot %u.\n", ts_nr);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rc = e1inp_line_update(e1_line);
 | 
					 | 
				
			||||||
	if (rc < 0) {
 | 
					 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", trunk->e1.vty_line_nr);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u closed.\n", ts_nr);
 | 
					 | 
				
			||||||
	trunk->e1.ts_usecount[ts_nr - 1]--;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -545,7 +496,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Equip E1 endpoint with I.460 mux and E1 timeslot resources.
 | 
					/*! Equip E1 endpoint with I.460 mux resources.
 | 
				
			||||||
 *  \param[in] endp endpoint to equip
 | 
					 *  \param[in] endp endpoint to equip
 | 
				
			||||||
 *  \param[in] ts E1 timeslot number.
 | 
					 *  \param[in] ts E1 timeslot number.
 | 
				
			||||||
 *  \param[in] ss E1 subslot number.
 | 
					 *  \param[in] ss E1 subslot number.
 | 
				
			||||||
@@ -566,7 +517,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
				
			|||||||
	endp->e1.last_amr_ft = AMR_4_75;
 | 
						endp->e1.last_amr_ft = AMR_4_75;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set up E1 line / timeslot */
 | 
						/* Set up E1 line / timeslot */
 | 
				
			||||||
	rc = e1_open(endp->trunk, ts);
 | 
						rc = e1_init(endp->trunk, ts);
 | 
				
			||||||
	if (rc != 0)
 | 
						if (rc != 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -653,15 +604,9 @@ void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Remove E1 resources from endpoint
 | 
					/*! Remove E1 resources from endpoint
 | 
				
			||||||
 *  \param[in] endp endpoint to release.
 | 
					 *  \param[in] endp endpoint to release. */
 | 
				
			||||||
 *  \param[in] ts E1 timeslot number. */
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Guard against multiple calls. In case we don't see a subchannel anymore we can safely assume that all work
 | 
					 | 
				
			||||||
	 * is done. */
 | 
					 | 
				
			||||||
	if (!(endp->e1.schan || endp->e1.trau_rtp_st || endp->e1.trau_sync_fi))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (endp->e1.schan)
 | 
						if (endp->e1.schan)
 | 
				
			||||||
@@ -670,10 +615,8 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
 | 
				
			|||||||
		talloc_free(endp->e1.trau_rtp_st);
 | 
							talloc_free(endp->e1.trau_rtp_st);
 | 
				
			||||||
	if (endp->e1.trau_sync_fi)
 | 
						if (endp->e1.trau_sync_fi)
 | 
				
			||||||
		osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
 | 
							osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
 | 
				
			||||||
	memset(&endp->e1, 0, sizeof(endp->e1));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Close E1 timeslot */
 | 
						memset(&endp->e1, 0, sizeof(endp->e1));
 | 
				
			||||||
	e1_close(endp->trunk, ts);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
 | 
					/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@
 | 
				
			|||||||
const struct mgcp_endpoint_typeset ep_typeset = {
 | 
					const struct mgcp_endpoint_typeset ep_typeset = {
 | 
				
			||||||
	/* Specify endpoint properties for RTP endpoint */
 | 
						/* Specify endpoint properties for RTP endpoint */
 | 
				
			||||||
	.rtp = {
 | 
						.rtp = {
 | 
				
			||||||
 | 
							.max_conns = 2,
 | 
				
			||||||
		.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
							.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
				
			||||||
		.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
 | 
							.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -109,6 +110,36 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
 | 
				
			|||||||
	return endp;
 | 
						return endp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! release endpoint, all open connections are closed.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to release */
 | 
				
			||||||
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We must only decrement the stat item when the endpoint as actually
 | 
				
			||||||
 | 
						 * claimed. An endpoint is claimed when a call-id is set */
 | 
				
			||||||
 | 
						if (endp->callid)
 | 
				
			||||||
 | 
							osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
 | 
				
			||||||
 | 
													 TRUNK_STAT_ENDPOINTS_USED), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
 | 
				
			||||||
 | 
							mgcp_e1_endp_release(endp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
 | 
					/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
 | 
				
			||||||
 * "ds/e1-") and write the epname without the prefix back to the memory
 | 
					 * "ds/e1-") and write the epname without the prefix back to the memory
 | 
				
			||||||
 * pointed at by epname. (per trunk the prefix is the same for all endpoints,
 | 
					 * pointed at by epname. (per trunk the prefix is the same for all endpoints,
 | 
				
			||||||
@@ -156,6 +187,7 @@ static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 /*! Convert all characters in epname to lowercase and strip trunk prefix and
 | 
					 /*! Convert all characters in epname to lowercase and strip trunk prefix and
 | 
				
			||||||
 * endpoint name suffix (domain name) from epname. The result is written to
 | 
					 * endpoint name suffix (domain name) from epname. The result is written to
 | 
				
			||||||
 * to the memory pointed at by epname_stripped. The expected size of the
 | 
					 * to the memory pointed at by epname_stripped. The expected size of the
 | 
				
			||||||
@@ -228,17 +260,6 @@ bool mgcp_endp_is_wildcarded(const char *epname)
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Check if the given epname refers to a "null" endpoint.
 | 
					 | 
				
			||||||
 *  \param[in] epname endpoint name to check
 | 
					 | 
				
			||||||
 *  \returns true if epname refers to "null"" endpoint, else false. */
 | 
					 | 
				
			||||||
bool mgcp_endp_is_null(const char *epname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (strncasecmp(epname, "null@", 5) == 0)
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Find an endpoint by its name on a specified trunk.
 | 
					/*! Find an endpoint by its name on a specified trunk.
 | 
				
			||||||
 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
					 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
				
			||||||
 *  \param[in] epname endpoint name to lookup.
 | 
					 *  \param[in] epname endpoint name to lookup.
 | 
				
			||||||
@@ -654,36 +675,3 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
				
			|||||||
	if (llist_empty(&endp->conns))
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
		mgcp_endp_release(endp);
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! release endpoint, all open connections are closed.
 | 
					 | 
				
			||||||
 *  \param[in] endp endpoint to release */
 | 
					 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* 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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We must only decrement the stat item when the endpoint as actually
 | 
					 | 
				
			||||||
	 * claimed. An endpoint is claimed when a call-id is set */
 | 
					 | 
				
			||||||
	if (endp->callid)
 | 
					 | 
				
			||||||
		osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
 | 
					 | 
				
			||||||
								 TRUNK_STAT_ENDPOINTS_USED), 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* 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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
					 | 
				
			||||||
		uint8_t ts = e1_ts_nr_from_epname(endp->name);
 | 
					 | 
				
			||||||
		mgcp_e1_endp_release(endp, ts);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,7 +75,7 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Parse connection mode.
 | 
					/*! Parse connection mode.
 | 
				
			||||||
 *  \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
 | 
					 *  \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
 | 
				
			||||||
 *  \param[in] endp pointer to endpoint (only used for log output)
 | 
					 *  \param[in] endp pointer to endpoint (only used for log output)
 | 
				
			||||||
 *  \param[out] associated connection to be modified accordingly
 | 
					 *  \param[out] associated connection to be modified accordingly
 | 
				
			||||||
 *  \returns 0 on success, -1 on error */
 | 
					 *  \returns 0 on success, -1 on error */
 | 
				
			||||||
@@ -100,8 +100,6 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
		conn->mode = MGCP_CONN_RECV_SEND;
 | 
							conn->mode = MGCP_CONN_RECV_SEND;
 | 
				
			||||||
	else if (strcasecmp(mode, "sendonly") == 0)
 | 
						else if (strcasecmp(mode, "sendonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_SEND_ONLY;
 | 
							conn->mode = MGCP_CONN_SEND_ONLY;
 | 
				
			||||||
	else if (strcasecmp(mode, "confecho") == 0)
 | 
					 | 
				
			||||||
		conn->mode = MGCP_CONN_CONFECHO;
 | 
					 | 
				
			||||||
	else if (strcasecmp(mode, "loopback") == 0)
 | 
						else if (strcasecmp(mode, "loopback") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_LOOPBACK;
 | 
							conn->mode = MGCP_CONN_LOOPBACK;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -492,24 +492,28 @@ void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* There may be different payload type numbers negotiated for two connections.
 | 
					/* There may be different payload type numbers negotiated for two connections.
 | 
				
			||||||
 * Patch the payload type of an RTP packet so that it uses the payload type
 | 
					 * Patch the payload type of an RTP packet so that it uses the payload type
 | 
				
			||||||
 * of the codec that is set for the destination connection (conn_dst) */
 | 
					 * that is valid for the destination connection (conn_dst) */
 | 
				
			||||||
static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
					static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
 | 
				
			||||||
 | 
								 struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
 | 
						uint8_t pt_in;
 | 
				
			||||||
 | 
						int pt_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
				
			||||||
		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "RTP packet too short (%u < %zu)\n",
 | 
							LOG_CONN_RTP(conn_src, LOGL_ERROR, "RTP packet too short (%u < %zu)\n",
 | 
				
			||||||
			     msgb_length(msg), sizeof(struct rtp_hdr));
 | 
								     msgb_length(msg), sizeof(struct rtp_hdr));
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn_dst->end.codec) {
 | 
						pt_in = rtp_hdr->payload_type;
 | 
				
			||||||
		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
 | 
						pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
 | 
				
			||||||
 | 
						if (pt_out < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_hdr->payload_type = (uint8_t) pt_out;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1130,11 +1134,12 @@ failed:
 | 
				
			|||||||
/*! Send RTP/RTCP data to a specified destination connection.
 | 
					/*! Send RTP/RTCP data to a specified destination connection.
 | 
				
			||||||
 *  \param[in] endp associated endpoint (for configuration, logging).
 | 
					 *  \param[in] endp associated endpoint (for configuration, logging).
 | 
				
			||||||
 *  \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
 | 
					 *  \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
 | 
				
			||||||
 *  \param[in] addr spoofed source address (set to NULL to disable).
 | 
					 *  \param[in] spoofed source address (set to NULL to disable).
 | 
				
			||||||
 *  \param[in] msg message buffer that contains the RTP/RTCP data.
 | 
					 *  \param[in] buf buffer that contains the RTP/RTCP data.
 | 
				
			||||||
 | 
					 *  \param[in] len length of the buffer that contains the RTP/RTCP data.
 | 
				
			||||||
 *  \param[in] conn_src associated source connection.
 | 
					 *  \param[in] conn_src associated source connection.
 | 
				
			||||||
 *  \param[in] conn_dst associated destination connection.
 | 
					 *  \param[in] conn_dst associated destination connection.
 | 
				
			||||||
 *  \returns 0 on success, negative on ERROR. */
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
 | 
					int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
 | 
				
			||||||
	      struct msgb *msg, struct mgcp_conn_rtp *conn_src,
 | 
						      struct msgb *msg, struct mgcp_conn_rtp *conn_src,
 | 
				
			||||||
	      struct mgcp_conn_rtp *conn_dst)
 | 
						      struct mgcp_conn_rtp *conn_dst)
 | 
				
			||||||
@@ -1164,9 +1169,18 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	 * IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
 | 
						 * IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
 | 
				
			||||||
	 * {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
 | 
						 * {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
 | 
				
			||||||
	if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
						if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
				
			||||||
		if (mgcp_patch_pt(conn_dst, msg) < 0) {
 | 
							rc = mgcp_patch_pt(conn_src, conn_dst, msg);
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE, "unable to patch payload type RTP packet, discarding...\n");
 | 
							if (rc < 0) {
 | 
				
			||||||
			return -EINVAL;
 | 
								/* FIXME: It is legal that the payload type on the egress connection is
 | 
				
			||||||
 | 
								 * different from the payload type that has been negotiated on the
 | 
				
			||||||
 | 
								 * ingress connection. Essentially the codecs are the same so we can
 | 
				
			||||||
 | 
								 * match them and patch the payload type. However, if we can not find
 | 
				
			||||||
 | 
								 * the codec pendant (everything ist equal except the PT), we are of
 | 
				
			||||||
 | 
								 * course unable to patch the payload type. A situation like this
 | 
				
			||||||
 | 
								 * should not occur if transcoding is consequently avoided. Until
 | 
				
			||||||
 | 
								 * we have transcoding support in osmo-mgw we can not resolve this. */
 | 
				
			||||||
 | 
								LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
									 "can not patch PT because no suitable egress codec was found.\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1290,10 +1304,8 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
	struct mgcp_conn_rtp *conn_src = mc->conn_src;
 | 
						struct mgcp_conn_rtp *conn_src = mc->conn_src;
 | 
				
			||||||
	struct mgcp_conn *conn = conn_src->conn;
 | 
						struct mgcp_conn *conn = conn_src->conn;
 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
	struct mgcp_endpoint *endp = conn->endp;
 | 
					 | 
				
			||||||
	struct osmo_sockaddr *from_addr = mc->from_addr;
 | 
						struct osmo_sockaddr *from_addr = mc->from_addr;
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int rc = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! NOTE: This callback function implements the endpoint specific
 | 
						/*! NOTE: This callback function implements the endpoint specific
 | 
				
			||||||
	 *  dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
 | 
						 *  dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
 | 
				
			||||||
@@ -1325,35 +1337,36 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the mode does not allow receiving RTP, we are done. */
 | 
						/* Find a destination connection. */
 | 
				
			||||||
	switch (conn->mode) {
 | 
						/* NOTE: This code path runs every time an RTP packet is received. The
 | 
				
			||||||
	case MGCP_CONN_RECV_ONLY:
 | 
						 * function mgcp_find_dst_conn() we use to determine the detination
 | 
				
			||||||
	case MGCP_CONN_RECV_SEND:
 | 
						 * connection will iterate the connection list inside the endpoint.
 | 
				
			||||||
	case MGCP_CONN_CONFECHO:
 | 
						 * Since list iterations are quite costly, we will figure out the
 | 
				
			||||||
		break;
 | 
						 * destination only once and use the optional private data pointer of
 | 
				
			||||||
	default:
 | 
						 * the connection to cache the destination connection pointer. */
 | 
				
			||||||
		return rc;
 | 
						if (!conn->priv) {
 | 
				
			||||||
 | 
							conn_dst = mgcp_find_dst_conn(conn);
 | 
				
			||||||
 | 
							conn->priv = conn_dst;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							conn_dst = (struct mgcp_conn *)conn->priv;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the mode is "confecho", send RTP back to the sender. */
 | 
						/* There is no destination conn, stop here */
 | 
				
			||||||
	if (conn->mode == MGCP_CONN_CONFECHO)
 | 
						if (!conn_dst) {
 | 
				
			||||||
		rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							LOGPCONN(conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "no connection to forward an incoming RTP packet to\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Dispatch RTP packet to all other connection(s) that send audio. */
 | 
						/* The destination conn is not an RTP connection */
 | 
				
			||||||
	llist_for_each_entry(conn_dst, &endp->conns, entry) {
 | 
						if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		if (conn_dst == conn)
 | 
							LOGPCONN(conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			continue;
 | 
								 "unable to find suitable destination conn\n");
 | 
				
			||||||
		switch (conn_dst->mode) {
 | 
							return -1;
 | 
				
			||||||
		case MGCP_CONN_SEND_ONLY:
 | 
					 | 
				
			||||||
		case MGCP_CONN_RECV_SEND:
 | 
					 | 
				
			||||||
		case MGCP_CONN_CONFECHO:
 | 
					 | 
				
			||||||
			rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
	return rc;
 | 
						/* Dispatch RTP packet to destination RTP connection */
 | 
				
			||||||
 | 
						return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
					/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,9 +86,6 @@ struct mgcp_request_data {
 | 
				
			|||||||
	/* set to true when the request has been classified as wildcarded */
 | 
						/* set to true when the request has been classified as wildcarded */
 | 
				
			||||||
	bool wildcarded;
 | 
						bool wildcarded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set to true when the request is targeted at the "null" endpoint */
 | 
					 | 
				
			||||||
	bool null_endp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* contains cause code in case of problems during endp/trunk resolution */
 | 
						/* contains cause code in case of problems during endp/trunk resolution */
 | 
				
			||||||
	int mgcp_cause;
 | 
						int mgcp_cause;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -393,9 +390,6 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
	/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
 | 
						/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
 | 
				
			||||||
	rq.pdata = &pdata;
 | 
						rq.pdata = &pdata;
 | 
				
			||||||
	rq.wildcarded = mgcp_endp_is_wildcarded(pdata.epname);
 | 
						rq.wildcarded = mgcp_endp_is_wildcarded(pdata.epname);
 | 
				
			||||||
	if (!rq.wildcarded)
 | 
					 | 
				
			||||||
		rq.null_endp = mgcp_endp_is_null(pdata.epname);
 | 
					 | 
				
			||||||
	if (!rq.null_endp)
 | 
					 | 
				
			||||||
	rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
 | 
						rq.endp = mgcp_endp_by_name(&rc, pdata.epname, pdata.cfg);
 | 
				
			||||||
	rq.mgcp_cause = rc;
 | 
						rq.mgcp_cause = rc;
 | 
				
			||||||
	if (!rq.endp) {
 | 
						if (!rq.endp) {
 | 
				
			||||||
@@ -413,14 +407,14 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
				     rq.name, pdata.epname);
 | 
									     rq.name, pdata.epname);
 | 
				
			||||||
				return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
									return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if (!rq.null_endp) {
 | 
							} else {
 | 
				
			||||||
			/* If the endpoint name suggests that the request refers to a specific endpoint, then the
 | 
								/* If the endpoint name suggests that the request refers to a specific endpoint, then the
 | 
				
			||||||
			 * request cannot be handled and we must stop early. */
 | 
								 * request cannot be handled and we must stop early. */
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
 | 
								     "%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
 | 
				
			||||||
			     pdata.epname, -rq.mgcp_cause);
 | 
								     pdata.epname, -rq.mgcp_cause);
 | 
				
			||||||
			return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
								return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
				
			||||||
		} /* else: Handle special "null" endpoint below (with rq.endp=NULL, rq.trunk=NULL) */
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
 | 
							osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
 | 
				
			||||||
		rq.trunk = rq.endp->trunk;
 | 
							rq.trunk = rq.endp->trunk;
 | 
				
			||||||
@@ -466,11 +460,6 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
 | 
					static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
						LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Auditing "null" endpoint is allowed for keepalive purposes. There's no rq->endp nor rq->trunk in this case. */
 | 
					 | 
				
			||||||
	if (rq->null_endp)
 | 
					 | 
				
			||||||
		return create_ok_response(rq->pdata->cfg, NULL, 200, "AUEP", rq->pdata->trans);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!rq->endp || !mgcp_endp_avail(rq->endp)) {
 | 
						if (!rq->endp || !mgcp_endp_avail(rq->endp)) {
 | 
				
			||||||
		LOGPENDP(rq->endp, DLMGCP, LOGL_ERROR, "AUEP: selected endpoint not available!\n");
 | 
							LOGPENDP(rq->endp, DLMGCP, LOGL_ERROR, "AUEP: selected endpoint not available!\n");
 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 501, "AUEP", rq->pdata->trans);
 | 
							return create_err_response(rq->trunk, NULL, 501, "AUEP", rq->pdata->trans);
 | 
				
			||||||
@@ -672,8 +661,8 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
		case 'a':
 | 
							case 'a':
 | 
				
			||||||
			/* FIXME: LCO also supports the negotiation of more than one codec.
 | 
								/* FIXME: LCO also supports the negotiation of more than one codec.
 | 
				
			||||||
			 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
								 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
				
			||||||
			 * codec only. Ignoring all but the first codec. */
 | 
								 * codec only. */
 | 
				
			||||||
			if (sscanf(lco_id + 1, ":%16[^,;]", codec) == 1) {
 | 
								if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
 | 
				
			||||||
				talloc_free(lco->codec);
 | 
									talloc_free(lco->codec);
 | 
				
			||||||
				/* MGCP header is case insensive, and we'll need
 | 
									/* MGCP header is case insensive, and we'll need
 | 
				
			||||||
				   codec in uppercase when using it later: */
 | 
									   codec in uppercase when using it later: */
 | 
				
			||||||
@@ -772,9 +761,6 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
			     struct mgcp_request_data *rq, int have_sdp, bool crcx)
 | 
								     struct mgcp_request_data *rq, int have_sdp, bool crcx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint *endp = rq->endp;
 | 
						struct mgcp_endpoint *endp = rq->endp;
 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_dst_rtp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	char *cmd;
 | 
						char *cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -816,15 +802,8 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Try to find an destination RTP connection that we can include in the codec decision. */
 | 
					 | 
				
			||||||
	conn_dst = mgcp_find_dst_conn(conn->conn);
 | 
					 | 
				
			||||||
	if (conn_dst && conn_dst->type == MGCP_CONN_TYPE_RTP)
 | 
					 | 
				
			||||||
		conn_dst_rtp = &conn_dst->u.rtp;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		conn_dst_rtp = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Make codec decision */
 | 
						/* Make codec decision */
 | 
				
			||||||
	if (mgcp_codec_decide(conn, conn_dst_rtp) != 0)
 | 
						if (mgcp_codec_decide(conn) != 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -866,7 +845,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	struct mgcp_parse_data *pdata = rq->pdata;
 | 
						struct mgcp_parse_data *pdata = rq->pdata;
 | 
				
			||||||
	struct mgcp_trunk *trunk = rq->trunk;
 | 
						struct mgcp_trunk *trunk = rq->trunk;
 | 
				
			||||||
	struct mgcp_endpoint *endp = rq->endp;
 | 
						struct mgcp_endpoint *endp = rq->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs;
 | 
						struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
 | 
				
			||||||
	int error_code = 400;
 | 
						int error_code = 400;
 | 
				
			||||||
	const char *local_options = NULL;
 | 
						const char *local_options = NULL;
 | 
				
			||||||
	const char *callid = NULL;
 | 
						const char *callid = NULL;
 | 
				
			||||||
@@ -880,14 +859,6 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->null_endp) {
 | 
					 | 
				
			||||||
		/* trunk not available so rate_ctr aren't available either. */
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "CRCX: Not allowed in 'null' endpoint!\n");
 | 
					 | 
				
			||||||
		return create_err_response(pdata->cfg, NULL, 502, "CRCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* we must have a free ep */
 | 
						/* we must have a free ep */
 | 
				
			||||||
	if (!endp) {
 | 
						if (!endp) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
 | 
				
			||||||
@@ -967,7 +938,7 @@ mgcp_header_done:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if we are able to accept the creation of another connection */
 | 
						/* Check if we are able to accept the creation of another connection */
 | 
				
			||||||
	if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns) {
 | 
						if (llist_count(&endp->conns) >= endp->type->max_conns) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			"CRCX: endpoint full, max. %i connections allowed!\n",
 | 
								"CRCX: endpoint full, max. %i connections allowed!\n",
 | 
				
			||||||
			endp->type->max_conns);
 | 
								endp->type->max_conns);
 | 
				
			||||||
@@ -1153,7 +1124,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	struct mgcp_parse_data *pdata = rq->pdata;
 | 
						struct mgcp_parse_data *pdata = rq->pdata;
 | 
				
			||||||
	struct mgcp_trunk *trunk = rq->trunk;
 | 
						struct mgcp_trunk *trunk = rq->trunk;
 | 
				
			||||||
	struct mgcp_endpoint *endp = rq->endp;
 | 
						struct mgcp_endpoint *endp = rq->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs;
 | 
						struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
 | 
				
			||||||
	char new_local_addr[INET6_ADDRSTRLEN];
 | 
						char new_local_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int error_code = 500;
 | 
						int error_code = 500;
 | 
				
			||||||
	int silent = 0;
 | 
						int silent = 0;
 | 
				
			||||||
@@ -1168,14 +1139,6 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->null_endp) {
 | 
					 | 
				
			||||||
		/* trunk not available so rate_ctr aren't available either. */
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MDCX: Not allowed in 'null' endpoint!\n");
 | 
					 | 
				
			||||||
		return create_err_response(pdata->cfg, NULL, 502, "MDCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (rq->wildcarded) {
 | 
						if (rq->wildcarded) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1293,10 +1256,6 @@ mgcp_header_done:
 | 
				
			|||||||
		error_code = rc;
 | 
							error_code = rc;
 | 
				
			||||||
		goto error3;
 | 
							goto error3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
 | 
					 | 
				
			||||||
	/* TODO: "codec" probably needs to be moved from endp to conn */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0)
 | 
					 | 
				
			||||||
		rc = mgcp_conn_iuup_init(conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check connection mode setting */
 | 
						/* check connection mode setting */
 | 
				
			||||||
	if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
						if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
				
			||||||
@@ -1391,7 +1350,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	struct mgcp_parse_data *pdata = rq->pdata;
 | 
						struct mgcp_parse_data *pdata = rq->pdata;
 | 
				
			||||||
	struct mgcp_trunk *trunk = rq->trunk;
 | 
						struct mgcp_trunk *trunk = rq->trunk;
 | 
				
			||||||
	struct mgcp_endpoint *endp = rq->endp;
 | 
						struct mgcp_endpoint *endp = rq->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs;
 | 
						struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
 | 
				
			||||||
	int error_code = 400;
 | 
						int error_code = 400;
 | 
				
			||||||
	int silent = 0;
 | 
						int silent = 0;
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
@@ -1401,18 +1360,10 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* NOTE: In this handler we can not take it for granted that the endp
 | 
						/* NOTE: In this handler we can not take it for granted that the endp
 | 
				
			||||||
	 * pointer will be populated, however a trunk is always guaranteed (except for 'null' endp).
 | 
						 * pointer will be populated, however a trunk is always guaranteed. */
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: deleting connection(s) ...\n");
 | 
						LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: deleting connection(s) ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->null_endp) {
 | 
					 | 
				
			||||||
		/* trunk not available so rate_ctr aren't available either. */
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "DLCX: Not allowed in 'null' endpoint!\n");
 | 
					 | 
				
			||||||
		return create_err_response(pdata->cfg, NULL, 502, "DLCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
 | 
					 | 
				
			||||||
	if (endp && !mgcp_endp_avail(endp)) {
 | 
						if (endp && !mgcp_endp_avail(endp)) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1563,12 +1514,6 @@ static struct msgb *handle_rsip(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
 | 
						LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->null_endp) {
 | 
					 | 
				
			||||||
		/* trunk not available so rate_ctr aren't available either. */
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "RSIP: Not allowed in 'null' endpoint!\n");
 | 
					 | 
				
			||||||
		return create_err_response(rq->pdata->cfg, NULL, 502, "RSIP", rq->pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rq->pdata->cfg->reset_cb)
 | 
						if (rq->pdata->cfg->reset_cb)
 | 
				
			||||||
		rq->pdata->cfg->reset_cb(rq->endp->trunk);
 | 
							rq->pdata->cfg->reset_cb(rq->endp->trunk);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
@@ -1594,12 +1539,6 @@ static struct msgb *handle_noti_req(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
 | 
						LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->null_endp) {
 | 
					 | 
				
			||||||
		/* trunk not available so rate_ctr aren't available either. */
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "RQNT: Not allowed in 'null' endpoint!\n");
 | 
					 | 
				
			||||||
		return create_err_response(rq->pdata->cfg, NULL, 502, "RQNT", rq->pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_line(line, rq->pdata->save) {
 | 
						for_each_line(line, rq->pdata->save) {
 | 
				
			||||||
		switch (toupper(line[0])) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'S':
 | 
							case 'S':
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,12 +239,13 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
 | 
				
			|||||||
		if (delimiter == ';' || delimiter == ',')
 | 
							if (delimiter == ';' || delimiter == ',')
 | 
				
			||||||
			str_ptr[strlen(str_ptr) - 1] = '\0';
 | 
								str_ptr[strlen(str_ptr) - 1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
 | 
							/* AMR octet aligned parameter */
 | 
				
			||||||
		if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
 | 
							if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
 | 
				
			||||||
			fmtp_param->param.amr_octet_aligned_present = true;
 | 
								fmtp_param->param.amr_octet_aligned_present = true;
 | 
				
			||||||
			fmtp_param->param.amr_octet_aligned = false;
 | 
								fmtp_param->param.amr_octet_aligned = false;
 | 
				
			||||||
			if (amr_octet_aligned == 1)
 | 
								if (amr_octet_aligned == 1)
 | 
				
			||||||
				fmtp_param->param.amr_octet_aligned = true;
 | 
									fmtp_param->param.amr_octet_aligned = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		param_str = strtok(NULL, " ");
 | 
							param_str = strtok(NULL, " ");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,6 +120,8 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
 | 
							trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " number endpoints %u%s",
 | 
						vty_out(vty, " number endpoints %u%s",
 | 
				
			||||||
		trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
							trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
				
			||||||
 | 
						vty_out(vty, " %sallow-transcoding%s",
 | 
				
			||||||
 | 
							trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
				
			||||||
	if (strlen(g_cfg->call_agent_addr))
 | 
						if (strlen(g_cfg->call_agent_addr))
 | 
				
			||||||
		vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
 | 
							vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
@@ -511,7 +513,6 @@ DEFUN_DEPRECATED(cfg_mgcp_bind_early,
 | 
				
			|||||||
		 BIND_STR
 | 
							 BIND_STR
 | 
				
			||||||
		 "Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
 | 
							 "Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'bind early (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -699,19 +700,25 @@ DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgcp_allow_transcoding,
 | 
					DEFUN_USRATTR(cfg_mgcp_allow_transcoding,
 | 
				
			||||||
	      cfg_mgcp_allow_transcoding_cmd,
 | 
						      cfg_mgcp_allow_transcoding_cmd,
 | 
				
			||||||
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
	      "allow-transcoding", "Allow transcoding\n")
 | 
						      "allow-transcoding", "Allow transcoding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 0;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
 | 
					DEFUN_USRATTR(cfg_mgcp_no_allow_transcoding,
 | 
				
			||||||
	      cfg_mgcp_no_allow_transcoding_cmd,
 | 
						      cfg_mgcp_no_allow_transcoding_cmd,
 | 
				
			||||||
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
	      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
						      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 1;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -722,7 +729,6 @@ DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
 | 
				
			|||||||
      "sdp audio-payload number <0-255>",
 | 
					      "sdp audio-payload number <0-255>",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Number\n" "Payload number\n")
 | 
					      SDP_STR AUDIO_STR "Number\n" "Payload number\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -736,7 +742,6 @@ DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_name,
 | 
				
			|||||||
      "sdp audio-payload name NAME",
 | 
					      "sdp audio-payload name NAME",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Name\n" "Payload name\n")
 | 
					      SDP_STR AUDIO_STR "Name\n" "Payload name\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -797,7 +802,6 @@ DEFUN_DEPRECATED(cfg_mgcp_loop,
 | 
				
			|||||||
		 "loop (0|1)",
 | 
							 "loop (0|1)",
 | 
				
			||||||
		 "Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
 | 
							 "Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1065,6 +1069,8 @@ static int config_write_trunk(struct vty *vty)
 | 
				
			|||||||
		if (trunk->audio_fmtp_extra)
 | 
							if (trunk->audio_fmtp_extra)
 | 
				
			||||||
			vty_out(vty, "   sdp audio fmtp-extra %s%s",
 | 
								vty_out(vty, "   sdp audio fmtp-extra %s%s",
 | 
				
			||||||
				trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
									trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "  %sallow-transcoding%s",
 | 
				
			||||||
 | 
								trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -1092,7 +1098,6 @@ DEFUN_DEPRECATED(cfg_trunk_payload_number,
 | 
				
			|||||||
      "sdp audio-payload number <0-255>",
 | 
					      "sdp audio-payload number <0-255>",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
 | 
					      SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1105,7 +1110,6 @@ DEFUN_DEPRECATED(cfg_trunk_payload_name,
 | 
				
			|||||||
      "sdp audio-payload name NAME",
 | 
					      "sdp audio-payload name NAME",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
 | 
					      SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1118,7 +1122,6 @@ DEFUN_DEPRECATED(cfg_trunk_loop,
 | 
				
			|||||||
		 "loop (0|1)",
 | 
							 "loop (0|1)",
 | 
				
			||||||
		 "Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
 | 
							 "Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1316,19 +1319,23 @@ DEFUN_ATTR(cfg_trunk_no_rtp_keepalive,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_trunk_allow_transcoding,
 | 
					DEFUN_USRATTR(cfg_trunk_allow_transcoding,
 | 
				
			||||||
	      cfg_trunk_allow_transcoding_cmd,
 | 
						      cfg_trunk_allow_transcoding_cmd,
 | 
				
			||||||
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
	      "allow-transcoding", "Allow transcoding\n")
 | 
						      "allow-transcoding", "Allow transcoding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 0;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_trunk_no_allow_transcoding,
 | 
					DEFUN_USRATTR(cfg_trunk_no_allow_transcoding,
 | 
				
			||||||
	      cfg_trunk_no_allow_transcoding_cmd,
 | 
						      cfg_trunk_no_allow_transcoding_cmd,
 | 
				
			||||||
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
	      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
						      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 1;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -360,7 +360,8 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* start telnet after reading config for vty_get_bind_addr() */
 | 
						/* start telnet after reading config for vty_get_bind_addr() */
 | 
				
			||||||
	rc = telnet_init_default(tall_mgw_ctx, NULL, OSMO_VTY_PORT_MGW);
 | 
						rc = telnet_init_dynif(tall_mgw_ctx, NULL,
 | 
				
			||||||
 | 
								       vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,11 +34,11 @@ DISTCLEANFILES = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ENABLE_EXT_TESTS
 | 
					if ENABLE_EXT_TESTS
 | 
				
			||||||
python-tests: $(top_builddir)/src/osmo-mgw/osmo-mgw
 | 
					python-tests: $(BUILT_SOURCES)
 | 
				
			||||||
	osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
						osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
				
			||||||
	osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
						osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
python-tests:
 | 
					python-tests: $(BUILT_SOURCES)
 | 
				
			||||||
	echo "Not running python-based tests (determined at configure-time)"
 | 
						echo "Not running python-based tests (determined at configure-time)"
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ AM_CFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	-no-install \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,8 +77,6 @@ static void test_strline(void)
 | 
				
			|||||||
#define AUEP1_RET "500 158663169 FAIL\r\n"
 | 
					#define AUEP1_RET "500 158663169 FAIL\r\n"
 | 
				
			||||||
#define AUEP2	"AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
 | 
					#define AUEP2	"AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
 | 
				
			||||||
#define AUEP2_RET "500 18983213 FAIL\r\n"
 | 
					#define AUEP2_RET "500 18983213 FAIL\r\n"
 | 
				
			||||||
#define AUEP_NULL "AUEP 18983215 null@mgw MGCP 1.0\r\n"
 | 
					 | 
				
			||||||
#define AUEP_NULL_RET "200 18983215 OK\r\n"
 | 
					 | 
				
			||||||
#define EMPTY	"\r\n"
 | 
					#define EMPTY	"\r\n"
 | 
				
			||||||
#define EMPTY_RET NULL
 | 
					#define EMPTY_RET NULL
 | 
				
			||||||
#define SHORT	"CRCX \r\n"
 | 
					#define SHORT	"CRCX \r\n"
 | 
				
			||||||
@@ -276,12 +274,6 @@ static void test_strline(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
 | 
					#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX_NULL \
 | 
					 | 
				
			||||||
	"MDCX 9 null@mgw MGCP 1.0\r\n" \
 | 
					 | 
				
			||||||
	"I: %s\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MDCX_NULL_RET "502 9 FAIL\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SHORT2	"CRCX 1"
 | 
					#define SHORT2	"CRCX 1"
 | 
				
			||||||
#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
					#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
				
			||||||
#define SHORT3	"CRCX 1 1@mgw"
 | 
					#define SHORT3	"CRCX 1 1@mgw"
 | 
				
			||||||
@@ -400,13 +392,6 @@ static void test_strline(void)
 | 
				
			|||||||
 #define DLCX_RET_OSMUX DLCX_RET \
 | 
					 #define DLCX_RET_OSMUX DLCX_RET \
 | 
				
			||||||
	"X-Osmo-CP: EC TI=0, TO=0\r\n"
 | 
						"X-Osmo-CP: EC TI=0, TO=0\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DLCX_NULL \
 | 
					 | 
				
			||||||
	"DLCX 8 null@mgw MGCP 1.0\r\n" \
 | 
					 | 
				
			||||||
	"I: %s\r\n" \
 | 
					 | 
				
			||||||
	"C: 2\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DLCX_NULL_RET "502 8 FAIL\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define RQNT \
 | 
					#define RQNT \
 | 
				
			||||||
	"RQNT 186908780 1@mgw MGCP 1.0\r\n" \
 | 
						"RQNT 186908780 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"X: B244F267488\r\n" \
 | 
						"X: B244F267488\r\n" \
 | 
				
			||||||
@@ -420,13 +405,6 @@ static void test_strline(void)
 | 
				
			|||||||
#define RQNT1_RET "200 186908780 OK\r\n"
 | 
					#define RQNT1_RET "200 186908780 OK\r\n"
 | 
				
			||||||
#define RQNT2_RET "200 186908781 OK\r\n"
 | 
					#define RQNT2_RET "200 186908781 OK\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RQNT_NULL \
 | 
					 | 
				
			||||||
	"RQNT 186908782 null@mgw MGCP 1.0\r\n" \
 | 
					 | 
				
			||||||
	"X: B244F267488\r\n" \
 | 
					 | 
				
			||||||
	"S: D/9\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PTYPE_IGNORE 0		/* == default initializer */
 | 
					#define PTYPE_IGNORE 0		/* == default initializer */
 | 
				
			||||||
#define PTYPE_NONE 128
 | 
					#define PTYPE_NONE 128
 | 
				
			||||||
#define PTYPE_NYI  PTYPE_NONE
 | 
					#define PTYPE_NYI  PTYPE_NONE
 | 
				
			||||||
@@ -567,20 +545,6 @@ static void test_strline(void)
 | 
				
			|||||||
	"m=audio 16008 RTP/AVP 0\r\n" \
 | 
						"m=audio 16008 RTP/AVP 0\r\n" \
 | 
				
			||||||
	"a=ptime:20\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_NULL \
 | 
					 | 
				
			||||||
	"CRCX 2 null@mgw MGCP 1.0\r\n" \
 | 
					 | 
				
			||||||
	"m: recvonly\r\n" \
 | 
					 | 
				
			||||||
	"C: 2\r\n" \
 | 
					 | 
				
			||||||
	"L: p:20\r\n" \
 | 
					 | 
				
			||||||
	"\r\n" \
 | 
					 | 
				
			||||||
	"v=0\r\n" \
 | 
					 | 
				
			||||||
	"c=IN IP4 123.12.12.123\r\n" \
 | 
					 | 
				
			||||||
	"m=audio 5904 RTP/AVP 97\r\n" \
 | 
					 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
					 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CRCX_NULL_RET "502 2 FAIL\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_test {
 | 
					struct mgcp_test {
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	const char *req;
 | 
						const char *req;
 | 
				
			||||||
@@ -622,11 +586,6 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
 | 
						{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
 | 
				
			||||||
	{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
 | 
						{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
 | 
				
			||||||
	{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
 | 
						{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
 | 
				
			||||||
	{"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
 | 
					 | 
				
			||||||
	{"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
 | 
					 | 
				
			||||||
	{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
 | 
					 | 
				
			||||||
	{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
 | 
					 | 
				
			||||||
	{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct mgcp_test retransmit[] = {
 | 
					static const struct mgcp_test retransmit[] = {
 | 
				
			||||||
@@ -1508,6 +1467,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
						/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 1;
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
					      sizeof(conn_id)) == 0);
 | 
										      sizeof(conn_id)) == 0);
 | 
				
			||||||
@@ -1551,6 +1511,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
				
			||||||
 | 
						trunk->no_audio_transcoding = 0;
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
					      sizeof(conn_id)) == 0);
 | 
										      sizeof(conn_id)) == 0);
 | 
				
			||||||
@@ -1808,25 +1769,26 @@ static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
 | 
				
			|||||||
	.amr_octet_aligned_present = false,
 | 
						.amr_octet_aligned_present = false,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct testcase_mgcp_codec_decide_codec {
 | 
					struct testcase_mgcp_codec_pt_translate_codec {
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	const char *audio_name;
 | 
						const char *audio_name;
 | 
				
			||||||
	const struct mgcp_codec_param *param;
 | 
						const struct mgcp_codec_param *param;
 | 
				
			||||||
	int expect_rc;
 | 
						int expect_rc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct testcase_mgcp_codec_decide_expect {
 | 
					struct testcase_mgcp_codec_pt_translate_expect {
 | 
				
			||||||
 | 
						bool end;
 | 
				
			||||||
	int payload_type_map[2];
 | 
						int payload_type_map[2];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct testcase_mgcp_codec_decide {
 | 
					struct testcase_mgcp_codec_pt_translate {
 | 
				
			||||||
	const char *descr;
 | 
						const char *descr;
 | 
				
			||||||
	/* two conns on an endpoint, each with N configured codecs */
 | 
						/* two conns on an endpoint, each with N configured codecs */
 | 
				
			||||||
	struct testcase_mgcp_codec_decide_codec codecs[2][10];
 | 
						struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
 | 
				
			||||||
	struct testcase_mgcp_codec_decide_expect expect[2];
 | 
						struct testcase_mgcp_codec_pt_translate_expect expect[32];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
 | 
					static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.descr = "same order, but differing payload type numbers",
 | 
							.descr = "same order, but differing payload type numbers",
 | 
				
			||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
@@ -1843,7 +1805,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {112, 96}, },
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
			{ .payload_type_map = {112, 96}, },
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1861,8 +1826,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
			{ .payload_type_map = {0, 0}, },
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 97}, },
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1880,8 +1848,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {0, 0}, },
 | 
					 | 
				
			||||||
			{ .payload_type_map = {96, 97}, },
 | 
								{ .payload_type_map = {96, 97}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {97, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1897,8 +1867,10 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {-EINVAL, -EINVAL}, },
 | 
								{ .payload_type_map = {112, -EINVAL}, },
 | 
				
			||||||
			{ .payload_type_map = {-EINVAL, 96}, },
 | 
								{ .payload_type_map = {0, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1915,60 +1887,28 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {112, -EINVAL}, },
 | 
								{ .payload_type_map = {112, -EINVAL}, },
 | 
				
			||||||
			{ .payload_type_map = {-EINVAL, -EINVAL}, },
 | 
								{ .payload_type_map = {0, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.descr = "test AMR with differing octet-aligned settings (both <-> both)",
 | 
							.descr = "test AMR with differing octet-aligned settings",
 | 
				
			||||||
		.codecs = {
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
				{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		.expect = {
 | 
					 | 
				
			||||||
			{ .payload_type_map = {111, 121}, },
 | 
					 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		.descr = "test AMR with differing octet-aligned settings (oa <-> both)",
 | 
					 | 
				
			||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
				{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 121}, },
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 121}, },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
 | 
							.descr = "test AMR with missing octet-aligned settings (defaults to 0)",
 | 
				
			||||||
		.codecs = {
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
				{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		.expect = {
 | 
					 | 
				
			||||||
			{ .payload_type_map = {112, 122}, },
 | 
					 | 
				
			||||||
			{ .payload_type_map = {112, 122}, },
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		.descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
 | 
					 | 
				
			||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
@@ -1979,54 +1919,22 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
 | 
							.descr = "test AMR with NULL param (defaults to 0)",
 | 
				
			||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		.expect = {
 | 
					 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
					 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		.descr = "test AMR with NULL param (oa <-> null)",
 | 
					 | 
				
			||||||
		.codecs = {
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", NULL, },
 | 
									{ 122, "AMR/8000", NULL, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
								{ .end = true },
 | 
				
			||||||
			{ .payload_type_map = {112, 122}, },
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		.descr = "test AMR with NULL param (bwe <-> null)",
 | 
					 | 
				
			||||||
		.codecs = {
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				{ 122, "AMR/8000", NULL, },
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		.expect = {
 | 
					 | 
				
			||||||
			/* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
 | 
					 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
					 | 
				
			||||||
			{ .payload_type_map = {112, 122}, },
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2044,8 +1952,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
			{ .payload_type_map = {0, 0}, },
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 97}, },
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2063,8 +1974,11 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
			{ .payload_type_map = {0, 0}, },
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 97}, },
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2082,73 +1996,21 @@ static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 121}, },
 | 
								{ .payload_type_map = {111, 121}, },
 | 
				
			||||||
			{ .payload_type_map = {111, 121} },
 | 
								{ .payload_type_map = {112, -EINVAL} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {113, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
 | 
					static void test_mgcp_codec_pt_translate(void)
 | 
				
			||||||
			   const struct testcase_mgcp_codec_decide_expect *expect)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	bool ok = true;
 | 
					 | 
				
			||||||
	int payload_type_conn_src;
 | 
					 | 
				
			||||||
	int payload_type_conn_dst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
 | 
					 | 
				
			||||||
	if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
 | 
					 | 
				
			||||||
		if (expect->payload_type_map[index_conn_src] == -EINVAL
 | 
					 | 
				
			||||||
		    && expect->payload_type_map[index_conn_dst] == -EINVAL)
 | 
					 | 
				
			||||||
			printf("    codec decision failed (expected)!\n");
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			printf("    ERROR: codec decision failed!\n");
 | 
					 | 
				
			||||||
			ok = false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		printf("    Codec decision result:\n");
 | 
					 | 
				
			||||||
		if (conn[index_conn_src].end.codec) {
 | 
					 | 
				
			||||||
			payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
 | 
					 | 
				
			||||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
					 | 
				
			||||||
			       index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			payload_type_conn_src = -EINVAL;
 | 
					 | 
				
			||||||
			printf("    conn[%u]: codec:none, pt:none\n", index_conn_src);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (conn[index_conn_dst].end.codec) {
 | 
					 | 
				
			||||||
			payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
 | 
					 | 
				
			||||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
					 | 
				
			||||||
			       index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
 | 
					 | 
				
			||||||
			       payload_type_conn_dst);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			payload_type_conn_dst = -EINVAL;
 | 
					 | 
				
			||||||
			printf("    conn[%u]: codec:none, pt:none\n", index_conn_dst);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
 | 
					 | 
				
			||||||
			printf("    ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
 | 
					 | 
				
			||||||
			       index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
 | 
					 | 
				
			||||||
			ok = false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
 | 
					 | 
				
			||||||
			printf("    ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
 | 
					 | 
				
			||||||
			       index_conn_dst, expect->payload_type_map[index_conn_dst],
 | 
					 | 
				
			||||||
			       payload_type_conn_dst);
 | 
					 | 
				
			||||||
			ok = false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ok;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void test_mgcp_codec_decide(void)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	bool ok = true;
 | 
						bool ok = true;
 | 
				
			||||||
	printf("\nTesting mgcp_codec_find_convertible()\n");
 | 
						printf("\nTesting mgcp_codec_pt_translate()\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
 | 
				
			||||||
		const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
 | 
							const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
 | 
				
			||||||
		struct mgcp_conn_rtp conn[2] = {};
 | 
							struct mgcp_conn_rtp conn[2] = {};
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
		int conn_i;
 | 
							int conn_i;
 | 
				
			||||||
@@ -2156,23 +2018,23 @@ static void test_mgcp_codec_decide(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		printf("#%d: %s\n", i, t->descr);
 | 
							printf("#%d: %s\n", i, t->descr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Build testvector (add codecs to conn, set properties etc... */
 | 
					 | 
				
			||||||
		for (conn_i = 0; conn_i < 2; conn_i++) {
 | 
							for (conn_i = 0; conn_i < 2; conn_i++) {
 | 
				
			||||||
			printf(" - add codecs on conn%d:\n", conn_i);
 | 
								printf(" - add codecs on conn%d:\n", conn_i);
 | 
				
			||||||
			for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
 | 
								for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
 | 
				
			||||||
				const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
 | 
									const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
 | 
				
			||||||
				if (!codec->audio_name)
 | 
									if (!codec->audio_name)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
 | 
									rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
 | 
				
			||||||
						    codec->param);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name,
 | 
									printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name,
 | 
				
			||||||
				       codec->param ?
 | 
									       codec->param ?
 | 
				
			||||||
					       (codec->param->amr_octet_aligned_present?
 | 
										       (codec->param->amr_octet_aligned_present?
 | 
				
			||||||
					(codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
 | 
												(codec->param->amr_octet_aligned ?
 | 
				
			||||||
 | 
													" octet-aligned=1" : " octet-aligned=0")
 | 
				
			||||||
							: " octet-aligned=unset")
 | 
												: " octet-aligned=unset")
 | 
				
			||||||
				       : "", rc);
 | 
											: "",
 | 
				
			||||||
 | 
											rc);
 | 
				
			||||||
				if (rc != codec->expect_rc) {
 | 
									if (rc != codec->expect_rc) {
 | 
				
			||||||
					printf("     ERROR: expected rc=%d\n", codec->expect_rc);
 | 
										printf("     ERROR: expected rc=%d\n", codec->expect_rc);
 | 
				
			||||||
					ok = false;
 | 
										ok = false;
 | 
				
			||||||
@@ -2182,17 +2044,36 @@ static void test_mgcp_codec_decide(void)
 | 
				
			|||||||
				printf("    (none)\n");
 | 
									printf("    (none)\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Run codec decision and check expectation */
 | 
							for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
 | 
				
			||||||
		if (!codec_decision(conn, 0, 1, &t->expect[0]))
 | 
								const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
 | 
				
			||||||
			ok = false;
 | 
								int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!codec_decision(conn, 1, 0, &t->expect[1]))
 | 
								if (expect->end)
 | 
				
			||||||
			ok = false;
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ok)
 | 
								result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
 | 
				
			||||||
			printf(" ===> SUCCESS: codec decision as expected!\n");
 | 
								printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
 | 
				
			||||||
		else
 | 
								       expect->payload_type_map[0], result);
 | 
				
			||||||
			printf(" ===> FAIL: unexpected codec decision!\n");
 | 
								if (result != expect->payload_type_map[1]) {
 | 
				
			||||||
 | 
									printf("     ERROR: expected -> %d\n", expect->payload_type_map[1]);
 | 
				
			||||||
 | 
									ok = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* If the expected result is an error, don't do reverse map test */
 | 
				
			||||||
 | 
								if (expect->payload_type_map[1] < 0)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
 | 
				
			||||||
 | 
								printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
 | 
				
			||||||
 | 
								       expect->payload_type_map[1], result);
 | 
				
			||||||
 | 
								if (result != expect->payload_type_map[0]) {
 | 
				
			||||||
 | 
									printf("     ERROR: expected -> %d\n", expect->payload_type_map[0]);
 | 
				
			||||||
 | 
									ok = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (conn_i = 0; conn_i < 2; conn_i++)
 | 
				
			||||||
 | 
								mgcp_codec_reset_all(&conn[conn_i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(ok);
 | 
						OSMO_ASSERT(ok);
 | 
				
			||||||
@@ -2352,7 +2233,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_osmux_cid();
 | 
						test_osmux_cid();
 | 
				
			||||||
	test_get_lco_identifier();
 | 
						test_get_lco_identifier();
 | 
				
			||||||
	test_check_local_cx_options(ctx);
 | 
						test_check_local_cx_options(ctx);
 | 
				
			||||||
	test_mgcp_codec_decide();
 | 
						test_mgcp_codec_pt_translate();
 | 
				
			||||||
	test_conn_id_matching();
 | 
						test_conn_id_matching();
 | 
				
			||||||
	test_e1_trunk_nr_from_epname();
 | 
						test_e1_trunk_nr_from_epname();
 | 
				
			||||||
	test_mgcp_is_rtp_dummy_payload();
 | 
						test_mgcp_is_rtp_dummy_payload();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -525,80 +525,6 @@ Response matches our expectations.
 | 
				
			|||||||
L: p:20
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
c=IN IP4 123.12.12.123
 | 
					 | 
				
			||||||
m=audio 5904 RTP/AVP 111
 | 
					 | 
				
			||||||
a=rtpmap:111 AMR/8000/1
 | 
					 | 
				
			||||||
a=ptime:20
 | 
					 | 
				
			||||||
a=fmtp:111 mode-change-capability=2; octet-align=1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
checking response:
 | 
					 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					 | 
				
			||||||
Response matches our expectations.
 | 
					 | 
				
			||||||
(response contains a connection id)
 | 
					 | 
				
			||||||
Dummy packets: 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
================================================
 | 
					 | 
				
			||||||
Testing AUEP_NULL
 | 
					 | 
				
			||||||
creating message from statically defined input:
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
AUEP 18983215 null@mgw MGCP 1.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
checking response:
 | 
					 | 
				
			||||||
using message as statically defined for comparison
 | 
					 | 
				
			||||||
Response matches our expectations.
 | 
					 | 
				
			||||||
(response does not contain a connection id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
================================================
 | 
					 | 
				
			||||||
Testing CRCX_NULL
 | 
					 | 
				
			||||||
creating message from statically defined input:
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
CRCX 2 null@mgw MGCP 1.0
 | 
					 | 
				
			||||||
m: recvonly
 | 
					 | 
				
			||||||
C: 2
 | 
					 | 
				
			||||||
L: p:20
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
v=0
 | 
					 | 
				
			||||||
c=IN IP4 123.12.12.123
 | 
					 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					 | 
				
			||||||
a=ptime:40
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
checking response:
 | 
					 | 
				
			||||||
using message as statically defined for comparison
 | 
					 | 
				
			||||||
Response matches our expectations.
 | 
					 | 
				
			||||||
(response does not contain a connection id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
================================================
 | 
					 | 
				
			||||||
Testing MDCX_NULL
 | 
					 | 
				
			||||||
creating message from statically defined input:
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
MDCX 9 null@mgw MGCP 1.0
 | 
					 | 
				
			||||||
I: %s
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
checking response:
 | 
					 | 
				
			||||||
using message as statically defined for comparison
 | 
					 | 
				
			||||||
Response matches our expectations.
 | 
					 | 
				
			||||||
(response does not contain a connection id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
================================================
 | 
					 | 
				
			||||||
Testing DLCX_NULL
 | 
					 | 
				
			||||||
creating message from statically defined input:
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
DLCX 8 null@mgw MGCP 1.0
 | 
					 | 
				
			||||||
I: %s
 | 
					 | 
				
			||||||
C: 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					 | 
				
			||||||
checking response:
 | 
					 | 
				
			||||||
using message as statically defined for comparison
 | 
					 | 
				
			||||||
Response matches our expectations.
 | 
					 | 
				
			||||||
(response does not contain a connection id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
================================================
 | 
					 | 
				
			||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 111
 | 
					m=audio 5904 RTP/AVP 111
 | 
				
			||||||
a=rtpmap:111 AMR/8000/1
 | 
					a=rtpmap:111 AMR/8000/1
 | 
				
			||||||
@@ -1350,7 +1276,7 @@ p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			|||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
Testing get_lco_identifier()
 | 
					Testing get_lco_identifier()
 | 
				
			||||||
p:10, a:PCMU -> p:10, a:PCMU
 | 
					p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			||||||
p:10, a:PCMU -> p:10, a:PCMU
 | 
					p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			||||||
'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
 | 
					'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
 | 
				
			||||||
'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
 | 
					'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
 | 
				
			||||||
'10,a:PCMU' -> 'a:PCMU'
 | 
					'10,a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
@@ -1360,15 +1286,13 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
', a:PCMU' -> 'a:PCMU'
 | 
					', a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
' a:PCMU' -> 'a:PCMU'
 | 
					' a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
'' -> '(null)'
 | 
					'' -> '(null)'
 | 
				
			||||||
p10, aPCMU -> (null)
 | 
					p10, aPCMU -> (null)
 | 
				
			||||||
'10,a :PCMU' -> '(null)'
 | 
					'10,a :PCMU' -> '(null)'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing mgcp_codec_find_convertible()
 | 
					Testing mgcp_codec_pt_translate()
 | 
				
			||||||
#0: same order, but differing payload type numbers
 | 
					#0: same order, but differing payload type numbers
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
@@ -1378,15 +1302,13 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
    conn[1]: codec:AMR, pt:96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
#1: different order and different payload type numbers
 | 
					#1: different order and different payload type numbers
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
@@ -1396,15 +1318,12 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
    conn[1]: codec:GSM-HR-08, pt:97
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
    conn[0]: codec:GSM-HR-08, pt:111
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
					#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    1:  96 GSM-HR-08/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    2:  97 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1:  96 GSM-HR-08/8000/1  -> rc=0
 | 
					    1:  96 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    2:  97 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2:  97 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
@@ -1412,13 +1331,9 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    conn[1]: codec:PCMU, pt:0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 96) -> 97
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
 | 
				
			||||||
    conn[1]: codec:GSM-HR-08, pt:97
 | 
					 | 
				
			||||||
    conn[0]: codec:GSM-HR-08, pt:96
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#3: conn0 has no codecs
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
@@ -1426,116 +1341,31 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    (none)
 | 
					    (none)
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    codec decision failed (expected)!
 | 
					    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    Codec decision result:
 | 
					    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    conn[1]: codec:AMR, pt:96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
    conn[0]: codec:none, pt:none
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#4: conn1 has no codecs
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					 | 
				
			||||||
    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    (none)
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 | 
				
			||||||
    conn[1]: codec:none, pt:none
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    codec decision failed (expected)!
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#5: test AMR with differing octet-aligned settings (both <-> both)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
#4: conn1 has no codecs
 | 
					#4: conn1 has no codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    Codec decision result:
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    conn[1]: codec:AMR, pt:121
 | 
					    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#6: test AMR with differing octet-aligned settings (oa <-> both)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 | 
				
			||||||
    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:121
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:121
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#7: test AMR with differing octet-aligned settings (bwe <-> both)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    (none)
 | 
					    (none)
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					#5: test AMR with differing octet-aligned settings
 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#8: test AMR with missing octet-aligned settings (oa <-> unset)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#9: test AMR with missing octet-aligned settings (bwe <-> unset)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:111
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#10: test AMR with NULL param (oa <-> null)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 112 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    0: 122 AMR/8000  -> rc=0
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 | 
				
			||||||
    Codec decision result:
 | 
					 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#11: test AMR with NULL param (bwe <-> null)
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
				
			||||||
@@ -1544,16 +1374,14 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
#7: test AMR with NULL param (defaults to 0)
 | 
					#7: test AMR with NULL param (defaults to 0)
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
    Codec decision result:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    conn[1]: codec:AMR, pt:122
 | 
					    0: 122 AMR/8000  -> rc=0
 | 
				
			||||||
    conn[0]: codec:AMR, pt:112
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
 | 
				
			||||||
#12: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
 | 
					#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0:  97 GSM-HR-08/8000  -> rc=0
 | 
					    0:  97 GSM-HR-08/8000  -> rc=0
 | 
				
			||||||
@@ -1562,16 +1390,14 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
    conn[1]: codec:GSM-HR-08, pt:97
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
    conn[0]: codec:GSM-HR-08, pt:111
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
#13: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
 | 
					#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0:  97 GSM-HR-08  -> rc=0
 | 
					    0:  97 GSM-HR-08  -> rc=0
 | 
				
			||||||
@@ -1579,15 +1405,10 @@ Testing mgcp_codec_find_convertible()
 | 
				
			|||||||
    2:  96 AMR octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
    Codec decision result:
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
    conn[1]: codec:GSM-HR-08, pt:97
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
    conn[0]: codec:GSM-HR-08, pt:111
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 ===> SUCCESS: codec decision as expected!
 | 
					 | 
				
			||||||
#14: test whether channel number matching is waterproof
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
    0: 111 GSM-HR-08/8000  -> rc=0
 | 
					 | 
				
			||||||
    1: 112 GSM-HR-08/8000/2  -> rc=-22
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
#10: test whether channel number matching is waterproof
 | 
					#10: test whether channel number matching is waterproof
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,6 @@ AM_CFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	-no-install \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ static struct msgb *from_str(const char *str)
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_client_conf *conf;
 | 
					static struct mgcp_client_conf conf;
 | 
				
			||||||
struct mgcp_client *mgcp = NULL;
 | 
					struct mgcp_client *mgcp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
 | 
					static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
 | 
				
			||||||
@@ -162,7 +162,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, conf);
 | 
						mgcp = mgcp_client_init(ctx, &conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n");
 | 
						printf("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -339,7 +339,7 @@ void test_mgcp_client_cancel(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, conf);
 | 
						mgcp = mgcp_client_init(ctx, &conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	trans_id = mgcp_msg_trans_id(msg);
 | 
						trans_id = mgcp_msg_trans_id(msg);
 | 
				
			||||||
@@ -630,7 +630,7 @@ void test_mgcp_client_e1_epname(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, conf);
 | 
						mgcp = mgcp_client_init(ctx, &conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Valid endpoint names */
 | 
						/* Valid endpoint names */
 | 
				
			||||||
	epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
 | 
				
			||||||
@@ -697,7 +697,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
 | 
						log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conf = mgcp_client_conf_alloc(ctx);
 | 
						mgcp_client_conf_init(&conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test_mgcp_msg();
 | 
						test_mgcp_msg();
 | 
				
			||||||
	test_mgcp_client_cancel();
 | 
						test_mgcp_client_cancel();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
					DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
DLMGCP MGW(mgw) Message buffer too small, can not generate MGCP message (SDP)
 | 
					DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
 | 
				
			||||||
DLMGCP MGW(mgw) Failed to add SDP, can not generate MGCP message
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_mgcp_client_cancel():
 | 
					test_mgcp_client_cancel():
 | 
				
			||||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
					DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
@@ -11,7 +10,6 @@ DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
 | 
				
			|||||||
- cancel succeeds
 | 
					- cancel succeeds
 | 
				
			||||||
DLMGCP MGW(mgw) Canceled transaction 1
 | 
					DLMGCP MGW(mgw) Canceled transaction 1
 | 
				
			||||||
- late response gets discarded
 | 
					- late response gets discarded
 | 
				
			||||||
DLMGCP MGW(mgw) MGCP link to MGW now considered UP
 | 
					 | 
				
			||||||
DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
 | 
					DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
 | 
				
			||||||
DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
 | 
					DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
 | 
				
			||||||
- canceling again does nothing
 | 
					- canceling again does nothing
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user